//ArrayScan RGB merger //This macro merges up to 4 channels to RBG images exported from ArrayScan automated microscope. //Optionally background substraction and auto-contrast can be adjusted for each channel //and in the manual mode the macro allows interactively to process each image manually. //first release 16-10-2013 by Martin Stöter (stoeter(at)mpi-cbg.de) html = "" +"ArrayScan RGB merger (release 2013-10-16)
" +"Check for help on this web page:
" +"http://idisk-srv1.mpi-cbg.de/knime/FijiUpdate/TDS_macros/ArrayScan_RGB_merger.htm
" +"...get this URL from Log window!
" +""; //start macro Dialog.create("Fiji macro: ArrayScan RGB merger"); Dialog.addMessage("Fiji macro: ArrayScan RGB merger (Fiji-Tools by TDS@MPI-CBG)\n \nThis macro creates RGB images from ArrayScan microscope exported .tif images (16-bit). \nClick 'OK' to go on, 'Cancel' to quit or 'Help' for online description."); Dialog.addHelp(html); print("http://idisk-srv1.mpi-cbg.de/knime/FijiUpdate/TDS%20macros/ArrayScan_RGB_merger.htm"); Dialog.show; //choose folders dir1 = getDirectory("Choose image folder... "); dir2 = getDirectory("Choose result image folder... or create a folder"); //set array variables for RGB merge availableRGBcolors = newArray("*None*","red", "green", "blue", "grey"); //possible color selections in pull-down colorsForRGBmerge = newArray("*None*", "*None*", "*None*", "*None*"); //array of color selection for channel 1-4 availableChannels = newArray("*None*", "Channel_0", "Channel_1", "Channel_2", "Channel_3"); //array of color selection for channel 1-4 channelsForRGBmerge =newArray(4); //choose colors for each channel Dialog.create("RGB merging"); for (i = 1; i <= 4; i++) Dialog.addChoice(availableRGBcolors[i], availableChannels); Dialog.addNumber("Number of fields per well for RGB:", 1); //set number of field for RBG images Dialog.addCheckbox("Adjust image contrast manually?", false); Dialog.addCheckbox("Set auto-contrast values?", false); Dialog.addCheckbox("Do background substraction?", false); Dialog.addCheckbox("Set batch mode (no images shown)?", false); Dialog.addString("Add prefix to all RGB image names:", ""); Dialog.addString("Add suffix to all RGB image names:", "_RGB"); Dialog.show(); for (i = 0; i < 4; i++) channelsForRGBmerge[i] = Dialog.getChoice(); numberOfFields = Dialog.getNumber(); manualMode = Dialog.getCheckbox(); autoContrast = Dialog.getCheckbox(); bkgCorrection = Dialog.getCheckbox(); batchMode = Dialog.getCheckbox(); rgbFilePrefix = Dialog.getString(); rgbFileSuffix = Dialog.getString(); saveRGB = true; //set variables for auto contrast and background corrections autoContrastValue = newArray(0.05, 0.05, 0.05, 0.05); bkgValue = newArray(100, 100, 100, 100); if (autoContrast) { Dialog.create("Set auto-contrast (0 = not applied)"); Dialog.addMessage("Set auto-contrast\nEnhance contast value (0-1, 0 = not applied)"); for (i = 1; i <= 4; i++) Dialog.addNumber(availableChannels[i], autoContrastValue[i-1]); Dialog.show(); for (i = 0; i < 4; i++) autoContrastValue[i] = Dialog.getNumber(); } if (bkgCorrection) { Dialog.create("Background substraction parameter (0 = not applied)"); Dialog.addMessage("Background substraction\nRolling ball radius (0 = not applied)"); for (i = 1; i <= 4; i++) Dialog.addNumber(availableChannels[i], bkgValue[i-1]); Dialog.show(); for (i = 0; i < 4; i++) bkgValue[i] = Dialog.getNumber(); } //initialize => default settings run("Set Measurements...", "area mean standard min centroid center shape integrated median display redirect=None decimal=3"); run("Input/Output...", "jpeg=75 gif=-1 file=.txt copy_column copy_row save_column save_row"); run("Close All"); setBatchMode((batchMode && !manualMode)); ////////////////// M A C R O : R G B - M E R G E A R R A Y S C A N I M A G E S /////////////////////////////// //get file list and well list fileList = getFileList(dir1); wellList = getAllWellsFuntion(fileList, true); exampleFileName = getImageFileExample(fileList); //create list field strings for file names fieldList = newArray(numberOfFields); for (i = 0; i < numberOfFields; i++) fieldList[i] = "f" + substring("0" + d2s(i,0),lengthOf("0" + d2s(i,0))-2,lengthOf("0" + d2s(i,0))); print("Input:", dir1, "\nOutput:", dir2); //now load well-field by well-field and merge to RGB for (currentWell = 0; currentWell < wellList.length; currentWell++) { for (currentField = 0; currentField < numberOfFields; currentField++) { for (channels = 0; channels < channelsForRGBmerge.length; channels++) { if (channelsForRGBmerge[channels] != "*None*") { currentChannel = parseInt(substring(channelsForRGBmerge[channels],lengthOf(channelsForRGBmerge[channels])-1,lengthOf(channelsForRGBmerge[channels]))); //get number of selected channel to be opened fileName = substring(exampleFileName,0,lengthOf(exampleFileName)-12) + wellList[currentWell] + fieldList[currentField] + "d" + currentChannel + substring(exampleFileName,lengthOf(exampleFileName)-4,lengthOf(exampleFileName)); //to log window print("well:", wellList[currentWell], ", field:", currentField, ", channel:", currentChannel, " file:", fileName); open(dir1 + fileName); rename("Channel_" + currentChannel); if (bkgCorrection && bkgValue[currentChannel] > 0) run("Subtract Background...", "rolling=" + bkgValue[currentChannel]); if (autoContrast && autoContrastValue[currentChannel] > 0) run("Enhance Contrast", "saturated=" + autoContrastValue[currentChannel]); //waitForUser("stop"); //debugging } } if (manualMode) { Dialog.create("Manual mode!"); //enable use inveractivity Dialog.addCheckbox("Stay in manual mode?", manualMode); Dialog.addString("Add prefix to all RGB image names:", rgbFilePrefix); Dialog.addString("Add suffix to all RGB image names:", rgbFileSuffix); Dialog.addCheckbox("Save RGB image", saveRGB); waitForUser("Adjust contrast manually, then 'OK'"); Dialog.show(); manualMode = Dialog.getCheckbox(); rgbFilePrefix = Dialog.getString(); rgbFileSuffix = Dialog.getString(); saveRGB = Dialog.getCheckbox(); } run("Merge Channels...", "red=" + channelsForRGBmerge[0] + " green=" + channelsForRGBmerge[1] + " blue=" + channelsForRGBmerge[2] + " gray=" + channelsForRGBmerge[3]); rgbImage = getImageID(); fileNameRGB = rgbFilePrefix + substring(exampleFileName,0,lengthOf(exampleFileName)-12) + wellList[currentWell] + fieldList[currentField] + rgbFileSuffix + ".png"; if (saveRGB) { saveAs("PNG", dir2 + fileNameRGB); print("Saved file:", fileNameRGB); } selectImage(rgbImage); close(); } } ///////////////////////////////////////////////////////////////////////////////////////////// //////// F U N C T I O N S ///////////// ///////////////////////////////////////////////////////////////////////////////////////////// function getAllWellsFuntion(fileList, closeWindow) { //function get all unique wells from a file list //the file list needs to be a list of files exported from ArrayScan/HCSView (.tif or .TIF) //the function goes through the sorted list and finds the well-text in file name (MFGTMP_131004100001_C02f00d1.TIF position 12 to 9 counted form end of file name => C02) //unique well-text and number of found images per well (fields x channels) are put to a list/array //message pops up information about number of wells found and their number of images, that will be closed then second parameter = true Array.sort(fileList); wellList = newArray(fileList.length); wellImageCountList = newArray(fileList.length); wellIndex = 0; wellImageCount = 0; currentFile = 0; do { if (endsWith(fileList[currentFile],".tif") || endsWith(fileList[currentFile],".TIF")){ //exclude metadata files wellImageCount++; if (wellIndex == 0) { //for first image found set current well currentWell = substring(fileList[currentFile],lengthOf(fileList[currentFile])-12,lengthOf(fileList[currentFile])-9); wellIndex = 1; } //for debugging: print(fileList[currentFile], currentFile, currentWell, wellList[wellIndex], wellIndex); //check if next image belongs to same well, if not put well and counted field-channel images in list if (currentWell != substring(fileList[currentFile+1],lengthOf(fileList[currentFile+1])-12,lengthOf(fileList[currentFile+1])-9)) { wellList[wellIndex-1] = currentWell; wellImageCountList[wellIndex-1] = wellImageCount; currentWell = substring(fileList[currentFile+1],lengthOf(fileList[currentFile+1])-12,lengthOf(fileList[currentFile+1])-9); wellImageCount = 0; wellIndex++; } } currentFile++; } while (currentFile < fileList.length); //for all files found //trim array lists and show in window wellList = Array.slice(wellList,0,wellIndex-1); wellImageCountList = Array.slice(wellImageCountList,0,wellIndex-1); //show result of well list Array.show(wellList,wellImageCountList); waitForUser("Number of well found: " + (wellIndex - 1) + "\n " + " \n" +"Check if number of wells and number of images in well" + "\n" + "are as expected! Otherwise press 'ESC' and check image list!"); //tidy up and close windows if (closeWindow) { windowList = getList("window.titles"); for (i = 0; i < windowList.length; i++) { if (windowList[i] == "Arrays") { selectWindow("Arrays"); run("Close"); } } } //end of function: return well list return wellList; } ///////////////////////////////////////////////////////////////////////////////////////////////// function getImageFileExample(fileList) { //function get an image file name as an example from a file list //the file list needs to have image file name with these extensoins: .tif or .TIF //message pops up if no image is found and macro is aborted currentFile = 0; do { if (endsWith(fileList[currentFile],".tif") || endsWith(fileList[currentFile],".TIF")){ //exclude metadata files //end of function: first image name return fileList[currentFile]; } currentFile++; } while (currentFile < fileList.length); //for all files found //show file list and abort macro Array.show(fileList); exit("No image files found!?" + "\n " + " \n" +"Check image list!"); } //////////////////////////////////////// E N D O F M A C R O ////////////////////////////