//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 ////////////////////////////