// Macro Stitch_Mosaic_SIM by Christophe Leterrier // v1.0 15/10/2014 from Stitch_Mosaic // Takes an input folder made of folders containing a number single or multi-channel tifs that have been taken as "mosaics" by hand (following an axon for example) // Includes option to read stage position from metadata for Nikon images (works directly on nd2 images) // Performs stiching using S. Preibisch's "Grid/Collection Stitching" plugin // part of Fiji see http://imagej.net/Image_Stitching#Grid.2FCollection_Stitching macro "Stitch_Mosaic_SIM" { // setOption("ExpandableArrays", true); posdata = true; // use stage position in image metadata (Nikon version) // For Nikon scope, stage position is in µm, while Grid/Collection stitching is in pixels PixelSize = 0.0325; // pixel size in µm for SIM // PixelSize = 0.16; // pixel size in µm for STORM // Definition of the Key for X and Y stage position in Nikon nd2 files xpos = "dXPos"; ypos = "dYPos"; // Scale for output mosaic (not kept by the stitcher) mosPixelUnit = "um"; mosPixelWidth = PixelSize; mosPixelHeight = PixelSize; // Get the folder name inDir = getDirectory("Select a directory full of mosaics as folders of tifs"); print("\n\n\n*** Stitch Mosaic SIM log ***"); print("input folder:" + inDir); // Get name of input folder, parent folder, short name of input folder (before first space in name) parDir = File.getParent(inDir); inName = File.getName(inDir); inShortA = split(inName, " "); inShort = inShortA[0]; setBatchMode(true); // Count the number of folders allFolders = getFileList(inDir); Array.sort(allFolders); dirN = 0; for (i = 0; i < allFolders.length; i++) { if (File.isDirectory(inDir + allFolders[i]) == 1 && indexOf(allFolders[i], "mosaic") < 0) { dirN ++; } } print("Number of mosaic folders in input folder:" + dirN); // Store the folder names in an array dirNames = newArray(dirN); dirc = 0; for (i = 0; i < allFolders.length; i++) { if (File.isDirectory(inDir + allFolders[i]) == 1 && indexOf(allFolders[i], "mosaic") < 0) { dirNames[dirc] = allFolders[i]; dirc ++; } } // Create mosaics folder mosDir = inDir + "mosaics" + File.separator; print("Mosaic folder: " + mosDir); if (File.isDirectory(mosDir) == false) { File.makeDirectory(mosDir); } //Loop on folders to process mosaics for (i = 0; i < dirNames.length; i++) { // Stitch all images in subfolder print("Processing folder: " + inDir + dirNames[i]); // if using stage positions in images metadata if (posdata == true) { // call the function to make the configuration file from stage position metadata in images (Nikon version) run("Bio-Formats Macro Extensions"); makeTileConfiguration(inDir + dirNames[i]); run("Grid/Collection stitching", "type=[Positions from file] order=[Defined by TileConfiguration] directory=[" + inDir + dirNames[i] +"] layout_file=TileConfiguration.txt fusion_method=[Linear Blending] regression_threshold=0.30 max/avg_displacement_threshold=2.50 absolute_displacement_threshold=3.50 compute_overlap subpixel_accuracy computation_parameters=[Save computation time (but use more RAM)] image_output=[Fuse and display]"); } else { run("Grid/Collection stitching", "type=[Unknown position] order=[All files in directory] directory=[" + inDir + dirNames[i] +"] output_textfile_name=TileConfiguration.txt fusion_method=[Linear Blending] regression_threshold=0.30 max/avg_displacement_threshold=2.50 absolute_displacement_threshold=3.50 ignore_z_stage subpixel_accuracy computation_parameters=[Save computation time (but use more RAM)] image_output=[Fuse and display]"); } // Apply stored scale run("Set Scale...", "distance=1 known=" + mosPixelWidth + " pixel=1 unit=" + mosPixelUnit); // Save resulting image fusedName = substring(dirNames[i], 0, lengthOf(dirNames[i]) - 1) + "_fused.tif"; rename(fusedName); save(mosDir + fusedName); print("Saved mosaic: " + mosDir + fusedName); //close(); } setBatchMode("exit and display"); print("\n\n\n*** Stitch Mosaic SIM has finished ***"); } function makeTileConfiguration(InputDir) { // Get all file names AllNames = getFileList(InputDir); Array.sort(AllNames); nL = AllNames.length; AllExt = newArray(nL); // Create extensions array and test if tif or nd2 ntif = 0; for (i = 0; i < nL; i++) { AllNamesParts = getFileExtension(AllNames[i]); AllExt[i] = AllNamesParts[1]; if (indexOf(toLowerCase(AllExt[i]), ".tif") > -1 || indexOf(toLowerCase(AllExt[i]), ".nd2") > -1) ntif++; // condition to catch .tif, .tiff, .TIF, .TIFF... or nd2 } NamesArray = newArray(ntif); XArray = newArray(ntif); YArray = newArray(ntif); j = 0; // counter to fill array (restricted to tif or nd2 files) // This gets the X,Y stage position for each image of the mosaic using BioFormat without opening the files for (i = 0; i -1 || indexOf(toLowerCase(AllExt[i]), ".nd2") > -1) { // Set ID, get the stage position metadata, store in the positions array Ext.setId( InputDir + AllNames[i]); Ext.getMetadataValue(xpos, XArray[j]); Ext.getMetadataValue(ypos, YArray[j]); // Assign name of the image NamesArray[j] = AllNames[i]; // Iterate tif counter j++; } } // Transform the coordinates from Nikon to pixels XArrayT = NikonToPixCoor(XArray, "X"); YArrayT = NikonToPixCoor(YArray, "Y"); // Write TileConfiguration.txt file writeTileConfiguration(NamesArray, XArrayT, YArrayT, InputDir); return; } function getFileExtension(Name) { nameparts = split(Name, "."); shortname = nameparts[0]; if (nameparts.length > 2) { for (k = 1; k < nameparts.length - 1; k++) { shortname += "." + nameparts[k]; } } extname = "." + nameparts[nameparts.length - 1]; namearray = newArray(shortname, extname); return namearray; } function NikonToPixCoor(ca, coor) { // output array oa = newArray(ca.length); // factor to adapt X and Y direction if (coor == "X") f = -1; else if (coor == "Y") f = 1; else factor = 1; for (i = 0; i < ca.length; i++) { // set center of the first image to 0, then convert from µm to pixels NewCoor = ((parseFloat(ca[i]) - parseFloat(ca[0])) / PixelSize) * f; // round with 1 decimal oa[i] = toString(NewCoor, 1); } return oa; } function writeTileConfiguration(nameA, xA, yA, fp) { // beginning of the file FileString = "# Define the number of dimensions we are working on\ndim = 2\n\n# Define the image coordinates\n"; // lines for each image and its coordinates for (n = 0; n < nameA.length; n++) { FileString += nameA[n] + "; ; (" + xA[n] + "," + yA[n] + ")\n"; } // save file File.saveString(FileString, fp + "TileConfiguration.txt"); }