/* Michael Cammer mcammer@gmail.com cammem01@nyumc.org Macros for ImageJ Java 1.8 This collection of macros are the ones I like to have on hand most of the time. More at http://microscopynotes.com/imagej/index.html Consider putting them in macros folder with name "StartupMacros.fiji.ijm" or "StartupMacros.ijm" so that they load automatically. Major updates as of Nov 2022 to add Z stack tools and clean up old code. See http://microscopynotes.com/imagej/selective_Z_project/index.html for instructions on how to use Z stack tools. */ var clipsize = 150; // edge size of the box for clipping cells for montage var snipwindow = -1; var projectiondepth = 16; // default depth for projection of variable depth var tab = " \t"; var scalebarSize = 10; // Scalebar size for simple merge with options //Require for Z projection macros var zstart = -1; // used by function selectiveZproject() var zend = -1; // used by function selectiveZproject() /* PULL DOWN MENU DEFINITIONS * Use this to add commands for Distal and Nucleus and adding line segments. * https://imagej.nih.gov/ij/macros/CustomPopupMenu.txt */ var pmCmds = newMenu("Popup Menu", newArray("First Slice", "Last Slice", "Project stack", "Show Overlays", "Hide Overlays", "Grays LUT", "Color LUT", "Brightness/Contrast...", "ROI Manager to front", "Save file as")); /* Right click on the image to get a pull down menu with useful commands. Easy to add * more commands as requested. */ macro "Popup Menu" { cmd = getArgument(); if (cmd == "First Slice") setFirstSlice(); if (cmd == "Last Slice") setLastSlice(); if (cmd == "Project stack") selectiveZproject(); if (startsWith(cmd, "Hide")) run("Hide Overlay"); if (startsWith(cmd, "Show")) run("Show Overlay"); if (startsWith(cmd, "Gray")) run("Grays"); if (startsWith(cmd, "Color")) makeFavoriteAIFpseudocolorLUT(); if (startsWith(cmd, "Bright")) run(cmd); if (startsWith(cmd, "ROI")) selectWindow("ROI Manager"); // does not work when minimized if (cmd == "Save file as") run("Tiff..."); } macro "Project stack with selective depth. [F11]" { selectiveZproject(); } /* * Projects a selective range of Z series. * This version leaves the original file unchanged. * If function is called without a user selection of start & stop poistions, then set to 1 to max Z slices. * If function is called with a ROI on image, then cropped to the area and outside cleared to zero. * This version works on multichannel (composite color) stacks including time series where the default * is project all timepoints. * */ function selectiveZproject() { Stack.getDimensions(width, height, channels, slices, frames); if (slices == 1) exit ("Requires a Z series."); title = getTitleStripExtension(); if (zstart < 1) zstart = 1; // If user has not made selection, then project entire stack. if (zend < 1) zend = slices; // If user has not made selection, then project entire stack. if (zend < zstart) { temp = zstart; zstart = zend; zend = temp; } // if selection, check selection type. If selection type good for cropping, then set flag to do crop after projection. selectionExists = false; if ((selectionType >=0) && (selectionType <= 4)) selectionExists = true; run("Z Project...", "start=" + zstart + " stop=" + zend + " projection=[Max Intensity] all"); rename (title + "_MAX" + zstart + "-" + zend); //If flag set for selection type, crop and clear. if (selectionExists) { run("Restore Selection"); run("Crop"); run("Make Inverse"); // instead of clear outside to avoid setcolor and bit depth issues run("Set...", "value=0 stack"); run("Make Inverse"); } zstart = -1; // reset for next use zend = -1; // reset for next use } /* The purpose of this tool is to set the current Z slice of a stack or hyperstack as the first slice * for a maximum pixel projection. * This can be set using the F9 key or the Macros pull down menu. * Or it can be done by clicking on the Z0 tool button and then clicking on the image. * A right click on image pull down menu option will be added later. */ macro "Set First Slice for projection [F9]" { setFirstSlice(); } function setFirstSlice() { Stack.getPosition(channel, slice, frame); zstart = slice; } /* The purpose of this tool is to set the current Z slice of a stack or hyperstack as the last slice * for a maximum pixel projection. * This can be set using the F10 key or the Macros pull down menu. * Or it can be done by clicking on the Z1 tool button and then clicking on the image. * A right click on image pull down menu option will be added later. */ macro "Set Last Slice for projection [F10]" { setLastSlice(); } function setLastSlice() { Stack.getPosition(channel, slice, frame); zend = slice; } macro "Click to set first, last, project Tool - N30 B08 C800 T4115Z " { //setClickToProject(); leftDivider = getWidth / 3; rightDivider = leftDivider * 2; getCursorLoc(x, y, z, flags); if (x < leftDivider) setFirstSlice(); if (x > rightDivider) setLastSlice(); if ( (x < rightDivider) && (x > leftDivider) ) selectiveZproject(); } macro "Click to set first, last, project Tool - N30 B08 C800 T4115Z " { //setClickToProject(); leftDivider = getWidth / 3; rightDivider = leftDivider * 2; getCursorLoc(x, y, z, flags); if (x < leftDivider) { Stack.getPosition(channel, slice, frame); zstart = slice; } if (x > rightDivider) { Stack.getPosition(channel, slice, frame); zstart = slice; } zend = z+1; if ( (x < rightDivider) && (x > leftDivider) ) selectiveZproject(); } macro "---------------------------------" {} /*=========================================================================== * ** Multichannel plot profile makes in register intensity plots of multiple channels and overlays them. * ** This produces a graphical result based on the deafult plot profile command where the plot of each * channel is the same LUT as in the image. * ** If the variable makeOutputTable = true, then a table is also created with the plot profiles * per channel. This table may be saved to import the data into other software. Set * makeOutputTable = false to turn off table reporting. * ** Macro works on multichannel images of any number. If you ever need more channels than assigned * to array processChannel, just add more. For spectral images from the Zeiss 880, more channels * may be required. * You may choose which channels to pot and which to not plot. In the array processChannel, 1 means plot * the channel and 0 means don't plot the channel. * ** If run on a hyperstack Z or T series, only the current T &/or Z is operated on. * ** Macro operates on the channels set to 1 in the array processChannel. * ** Original LUTs are kept and applied. =============================================================================*/ macro "Multichannel plot profile" { //add error check for line makeOutputTable = true; // set to false if don't want output table processChannel = newArray(1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0); // choose which channels to plot or not plot Stack.getDimensions(width, height, channels, slices, frames); original = getImageID; t = getTitleStripExtension(); mergeString = ""; newChannelNumber = 1; newExecution = true; for (c=1; c<=channels; c++) { if (processChannel[c-1]) { selectImage(original); Stack.setChannel(c); Color.getLut(reds, greens, blues); if (makeOutputTable) { profile = getProfile(); if (newExecution) { // create a new output table getPixelSize(unit, pixelWidth, pixelHeight); run("Set Measurements...", "area redirect=None decimal=2"); run("Measure"); distances = newArray(profile.length); pixelSize = getResult("Length", nResults-1) / profile.length; // um per pixel for(d=0; d1) || (frames>1) ) exit("Only works for single Z, time, or position images.\nAsk for modification if you need implemented."); if ( (slices > 1) || (frames > 1) ) exit("Requires single Z and single timepoint image"); if (channels < 2) exit("Requires composite color image."); title = getTitleStripExtension(); if (channels < 2) exit("Not a composite image with 2 or more channels."); if (channels == 2) { Dialog.create("get montage info"); Dialog.addNumber("Size of scalebar ("+unit+"): ", scalebarSize); Dialog.show; scalebarSize = Dialog.getNumber(); montageX=3; montageY=1; } if (channels == 3) { Dialog.create("get montage info"); //Dialog.addMessage(); Dialog.create("Radio Buttons"); items = newArray("One row of four panels", "2 X 2 panels"); Dialog.addRadioButtonGroup("Three channels will result in four panels.\nClick which layout preferred.", items, 2, 1, ""); Dialog.addNumber("Size of scalebar ("+unit+"): ", scalebarSize); Dialog.show; if ( Dialog.getRadioButton == "One row of four panels") { montageX=4; montageY=1; } else { montageX=2; montageY=2; } scalebarSize = Dialog.getNumber(); } if ((channels==4) || (channels==5)) { Dialog.create("get montage info"); Dialog.create("Radio Buttons"); items = newArray("One row of panels", "3 X 2 panels"); Dialog.addRadioButtonGroup("Click which layout preferred.", items, 2, 1, ""); Dialog.addNumber("Size of scalebar ("+unit+"): ", scalebarSize); Dialog.show; if ( Dialog.getRadioButton == "One row of panels") { montageX=channels+1; montageY=1; } else { montageX=3; montageY=2; } scalebarSize = Dialog.getNumber(); } if (channels > 5) exit("Not programmed for more than 5 channels; ask for modification if you need this."); simpleMergeAndMontageWithOptions (title, montageX, montageY); } macro "Make RGB into Grayscale" { originalImage = getImageID(); run("Duplicate...", " "); rename("TEMP"); run("RGB Stack"); run("Z Project...", "projection=[Max Intensity]"); rename("TEMP2"); run("RGB Color"); run("Select All"); run("Copy"); close("TEMP*"); selectImage(originalImage); run("Paste"); run("Select None"); } /* ========================================= WITH OPTIONS This function does the work of montaging. It takes a number of arguments. title = text Title of the image, will have montage added to it. montageX = integer How many columns in montage. montageY = integer How many rows in montage. To be implemented in future: grayscale = true/false To be coded someday. This directs the function whether to use LUTs as is or make individual panels in grayscale. */ function simpleMergeAndMontageWithOptions (title, montageX, montageY) { run("Duplicate...", "duplicate"); rename(title); original = getImageID; run("RGB Color"); // This should make a new window run("Select All"); run("Copy"); setPasteMode("Copy"); close(); selectImage(original); Stack.setDisplayMode("color"); run("RGB Color"); run("Hyperstack to Stack"); setSlice(nSlices); run("Add Slice"); run("Paste"); run("Scale Bar...", "width="+scalebarSize+" height=4 font=14 color=[White] background=None location=[Lower Right] bold"); run("Colors...", "foreground=white background=black selection=yellow"); if ((nSlices==5) & (montageY == 2)) { // Make the last panel white if 3 x 2 with only five panels. run("Add Slice"); run("Select All"); run("Fill", "slice"); } run("Select None"); run("Make Montage...", "columns="+montageX+" rows="+montageY+" scale=1 border=2 use"); rename(title+"_montage"); close(title); close(title+" (RGB)"); //Following steps copy the result to the system clipboard for pasting into another application. Only tested on win7. run("Select All"); run("Copy to System"); run("Select None"); } /* ============================================================ SIMPLE FIGURE BASED ON MULTICHANNEL IMAGE DISPLAYED AS IS version 20180930 Makes a montage figure based on a composite image as displayed. The required input is a composite color image. Use adjusts the channels to desied colors and contrast. Running the macro either merges an entire image or the region of interest selected by user. Uses existing contrast without further prompts. But there is a prompt when there are 3, or more channels to find out whether all images in one row or two rows. */ macro "Simple montage figure" { requires("1.52f"); Stack.getDimensions(width, height, channels, slices, frames); if ( (slices>1) || (frames>1) ) exit("Only works for single Z, time, or position images.\nAsk for modification if you need implemented."); if ( (slices > 1) || (frames > 1) ) exit("Requires single Z and single timepoint image"); if (channels < 2) exit("Requires composite color image."); title = getTitleStripExtension(); if (channels < 2) exit("Not a composite image with 2 or more channels."); if (channels == 2) { montageX=3; montageY=1; } if (channels == 3) { Dialog.create("get montage info"); //Dialog.addMessage(); Dialog.create("Radio Buttons"); items = newArray("One row of four panels", "2 X 2 panels"); Dialog.addRadioButtonGroup("Three channels will result in four panels.\nClick which layout preferred.", items, 2, 1, ""); Dialog.show; if ( Dialog.getRadioButton == "One row of four panels") { montageX=4; montageY=1; } else { montageX=2; montageY=2; } } if ((channels==4) || (channels==5)) { Dialog.create("get montage info"); Dialog.create("Radio Buttons"); items = newArray("One row of panels", "3 X 2 panels"); Dialog.addRadioButtonGroup("Click which layout preferred.", items, 2, 1, ""); Dialog.show; if ( Dialog.getRadioButton == "One row of panels") { montageX=channels+1; montageY=1; } else { montageX=3; montageY=2; } } if (channels > 5) exit("Not programmed for more than 5 channels; ask for modification if you need this."); simpleMergeAndMontage (title, montageX, montageY); } /* ========================================= This function does the work for Simple merge as is. It takes a number of arguments. title = text Title of the image, will have montage added to it. montageX = integer How many columns in montage. montageY = integer How many rows in montage. To be implemented in future: grayscale = true/false To be coded someday. This directs the function whether to use LUTs as is or make individual panels in grayscale. */ function simpleMergeAndMontage (title, montageX, montageY) { run("Duplicate...", "duplicate"); rename(title); original = getImageID; run("RGB Color"); // This should make a new window run("Select All"); run("Copy"); setPasteMode("Copy"); close(); selectImage(original); Stack.setDisplayMode("color"); run("RGB Color"); run("Hyperstack to Stack"); setSlice(nSlices); run("Add Slice"); run("Paste"); run("Scale Bar...", "width=10 height=4 font=14 color=[White] background=None location=[Lower Right] bold"); run("Colors...", "foreground=white background=black selection=yellow"); if ((nSlices==5) & (montageY == 2)) { // Make the last panel white if 3 x 2 with only five panels. run("Add Slice"); run("Select All"); run("Fill", "slice"); } run("Select None"); run("Make Montage...", "columns="+montageX+" rows="+montageY+" scale=1 border=2 use"); rename(title+"_montage"); close(title); close(title+" (RGB)"); //Following steps copy the result to the system clipboard for pasting into another application. Only tested on win7. run("Select All"); run("Copy to System"); run("Select None"); } //=========================================================================== // This macro takes all open stacks and projects them. Depending on the filename, in this case // "C=#", the projection method may be different. The projection command automatically names // the new windows with the type of projection followed by the original filename. //=========================================================================== macro "Project all open stacks" { projectAllOpenStacks(); } // "Project all open stacks" function projectAllOpenStacks(){ n = nImages(); for (i=1; i<=n; i++) { selectImage(i); t = getTitleStripExtension(); if ( endsWith(getTitle(), "C=2") ) run("Z Project...", "start=1 stop="+nSlices+" projection=[Min Intensity]"); else run("Z Project...", "start=1 stop="+nSlices+" projection=[Max Intensity]"); rename(t+"_proj"); } // for i } // end projectAllOpenStacks() //=============================================================================== // Extracts the nth slice from a timelapse or Z stack. //=============================================================================== macro "Extract nth slices from stacks" { extract_all_nth_timepoints(2); // change the number in this command to the required slice } function extract_all_nth_timepoints(extract) { // extract is an integer between 1 and nSlices n = nImages(); for (i=1; i<=n; i++) { selectImage(i); t = getTitleStripExtension(); setSlice(extract); title = "M" + extract + "_" + getTitle; run("Duplicate...", "title="+title); rename(t+"_s" + extract); } // for i } macro "=========================="{} //============================================================== // This is for when you already have color images. //macro "box location" { // getCursorLoc(x, y, z, mousestate); // makeRectangle(x-(boxsize/2),y-(boxsize/2), boxsize, boxsize); //} macro "Make snipping box" { makeRectangle(10,10, clipsize, clipsize); } //============================================================== macro "snip out the box [F5]" { roiManager("Add"); run("Duplicate...", "title=[snip]"); } //============================================================================= // calls function clipCellAndPopOnStack(original, clipstack); // macro "clip all ROIs in Roi Manager, center, and put in stack for montage" { original = getImageID; t = getTitle; bits = bitDepth(); if (bits == 24) bitstring="RGB"; else bitstring = ""+bits+"-bit"; clipsize = getNumber("Enter side of square box in pixels: ", clipsize); setPasteMode("Copy"); setBatchMode(true); newImage("snippedstack "+ t, bitstring+" Black", clipsize, clipsize, 1); clipstack = getImageID; for (i=0; iOptions>Colors... //4. Run this macro. // macro "draw ROI on range of slices in stack"{ checkCurrentVersion(); image_to_process = getImageID(); Dialog.create("draw on slices..."); Dialog.addNumber("first slice to draw on", 1); Dialog.addNumber("last slice to draw on", nSlices()); Dialog.show(); first = Dialog.getNumber(); last = Dialog.getNumber(); if (last < first) { temp=first; first=last; last=temp; } if (first < 1) exit("first slice must be 1 or greater"); if (last > nSlices()) exit("last slice must be the stack size or smaller"); n = roiManager("count"); // get the last ROI in the manager selectImage(image_to_process); roiManager("select", n-1); for (i=first; i<=last; i++){ setSlice(i); run("Draw", "slice"); } // for loop run("Select None"); resetMinAndMax(); } // draw ROI on range of slices in stack //============================================== macro "shift channel fixed amount to correct registration" { ch = 2; xoffset = -4; yoffset = 5; setPasteMode("Copy"); getDimensions(width, height, channels, slices, frames); for (f=1; f<=frames; f++){ Stack.setFrame(f); Stack.setChannel(ch); run("Select All"); run("Copy"); Roi.move(xoffset, yoffset); run("Paste"); } run("Select None"); } //===================================================================================== // This macro is not ready for general use because it requires programming to work right. // In its current state it moves the field a fixed amount per step and this amount is 1/22. macro "Drift Compensation" { setPasteMode("Copy"); for (i=0; i= (1/ratio) ) { newWidth = w + (border * w); newHeight = newWidth * ratio; } else { newHeight = h + (border * h); newWidth = newHeight / ratio; } run("Colors...", "foreground=black background=white selection=yellow"); // border color is background; change to any color as desired run("Canvas Size...", "width="+newWidth+" height="+newHeight+" position=Center"); } /* =============================================== A future version would have an if statement to check image type and also work on composite images. */ macro "EQ each channel of RGB image" { path = getDirectory("image"); run("RGB Stack"); setSlice(1); run("Enhance Contrast...", "saturated=0 equalize"); setSlice(2); run("Enhance Contrast...", "saturated=0 equalize"); setSlice(3); run("Enhance Contrast...", "saturated=0 equalize"); run("RGB Color"); title = "eq_" + getTitle(); rename(title); // save the new image run("Input/Output...", "jpeg=100 gif=-1 file=.txt use_file copy_column copy_row save_column save_row"); saveAs("Jpeg", path + title); } macro "=====Additional LUTs======"{} /* Additional LUT macros for ImageJ by Michael Cammer Please feel free to use as needed. Other resources: http://imagej.nih.gov/ij/download/luts/ http://rsb.info.nih.gov/ij/macros/ */ //=========================================== macro "Recolor with ratio LUT [F6]"{ makeFavoriteAIFpseudocolorLUT(); } function makeFavoriteAIFpseudocolorLUT(){ red = newArray(0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,120,112,104,96,88,80,72,64,56,48,40,32,24,16,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63,67,71,75,79,83,87,91,95,99,103,107,111,115,119,123,127,131,135,139,143,147,151,155,159,163,167,171,175,179,183,187,191,195,199,203,207,211,215,219,223,227,231,235,239,243,247,251,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255); green = newArray(0,1,2,3,4,5,6,7,8,9,10,9,9,8,8,7,7,6,6,5,5,5,4,4,3,3,2,2,1,1,0,0,0,7,15,23,31,39,47,55,63,71,79,87,95,103,111,119,127,135,143,151,159,167,175,183,191,199,207,215,223,231,239,247,255,247,239,231,223,215,207,199,191,183,175,167,159,151,143,135,128,129,131,132,134,135,137,139,140,142,143,145,147,148,150,151,153,154,156,158,159,161,162,164,166,167,169,170,172,174,175,177,178,180,181,183,185,186,188,189,191,193,194,196,197,199,201,202,204,205,207,208,210,212,213,215,216,218,220,221,223,224,226,228,229,231,232,234,235,237,239,240,242,243,245,247,248,250,251,253,255,251,247,243,239,235,231,227,223,219,215,211,207,203,199,195,191,187,183,179,175,171,167,163,159,155,151,147,143,139,135,131,127,123,119,115,111,107,103,99,95,91,87,83,79,75,71,67,63,59,55,51,47,43,39,35,31,27,23,19,15,11,7,3,0,8,16,24,32,41,49,57,65,74,82,90,98,106,115,123,131,139,148,156,164,172,180,189,197,205,213,222,230,238,246,254); blue = newArray(0,7,15,23,31,39,47,55,63,71,79,87,95,103,111,119,127,135,143,151,159,167,175,183,191,199,207,215,223,231,239,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,251,247,243,239,235,231,227,223,219,215,211,207,203,199,195,191,187,183,179,175,171,167,163,159,155,151,147,143,139,135,131,128,126,124,122,120,118,116,114,112,110,108,106,104,102,100,98,96,94,92,90,88,86,84,82,80,78,76,74,72,70,68,66,64,62,60,58,56,54,52,50,48,46,44,42,40,38,36,34,32,30,28,26,24,22,20,18,16,14,12,10,8,6,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,16,24,32,41,49,57,65,74,82,90,98,106,115,123,131,139,148,156,164,172,180,189,197,205,213,222,230,238,246,254); setLut(red, green, blue); } //=========================================== macro "Orange"{ // This was written before FiJi had an orange command included, still not in pull down LUTs menu (Nov 2022) orange(); } function orange() { red = newArray(256); green = newArray(256); blue = newArray(256); for (i=0; i<256; i++) { red[i] = i; green[i] = i / 2; blue[i] = 0; } // for i setLut(red, green, blue); } //=========================================== macro "Light blue (dapi)"{ lightBlue(); } function lightBlue() { red = newArray(256); green = newArray(256); blue = newArray(256); for (i=0; i<256; i++) { red[i] = 0; green[i] = i / 1.75; blue[i] = i; } // for i setLut(red, green, blue); } //=========================================== macro "HiLo"{ // This was written before FiJi had a HiLo LUT included mcHiLoLUT(); } function mcHiLoLUT() { red = newArray(256); green = newArray(256); blue = newArray(256); for (i=0; i<256; i++) { red[i] = i; green[i] = i; blue[i] = i; } // for i blue[255] = 0; blue[0] = 255; green[255] = 63; setLut(red, green, blue); } /* ============================================================= Standard ImageJ allows for installing macros from the macro editor text window by typing ctrl i. Fiji does not. Therefore, to easily update macros in Fiji, change the path of the current macro file being edited in this macro and use ctrl s followed by F4 to reinstall the macros from the Fiji text editor. */ macro "Install Macros [F4]" { run("Install...", "install=[C:/Users/cammem01/OneDrive - NYU Langone Health/_webpages_microscopynotes/imagej/macros/useful_collection_v100.ijm]"); }