User Tools

Site Tools


macro:platemontage

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

macro:platemontage [2019/04/12 11:13] (current)
Line 1: Line 1:
 +====== PlateMontage ======
  
 +** Creates a labeled plate montage image from BD Pathway 855 / AttoVision 1.6 data sets **
 +
 +<code java>
 +/* PlateMontage macro */ var version ​ = '1.4a, 2009-10-13';​
 +//
 +// Creates a labeled plate montage image from BD Pathway 855 / AttoVision 1.6 data sets
 +//
 +// Features:
 +//   ​Borders do not hide part of the images as in AttoVision
 +//   ​Simultaneous processing of up to three channels
 +//   ​Automatically saves the montage
 +//   Style is customizable
 +//   Well images can be inverted
 +//   ​Missing images are not a problem
 +//   All settings are remembered
 +//
 +// Shortcuts:
 +//   ​Shift-P:​ Run this macro
 +//   ​Shift-C:​ Close all windows
 +//   ​Shift-M:​ Reload this macro
 +//
 +// System requirements:​
 +//   The screen height must be at least 1024 pixels
 +//
 +// BD Pathway 855 / AttoVision data set directory structure:
 +//   + 2009-09-20 exp 328
 +//     + 2009-09-21_000
 +//       + Well A001
 +//           Alexa 488 - n000000.tif
 +//           Alexa 594 - n000000.tif
 +//           ​Hoechst - n000000.tif
 +//
 +// Contact: njensen@mail.unc.edu
 +// This code has been released into the Public Domain (PD)
 +
 +
 +// global constants
 +var settingsFile ​  = '​PlateMontageSettings.txt';​
 +var borderWidth ​   = 3;
 +var labelHeight ​   = 80;
 +var labelWidth ​    = 60;
 +var labelFont ​     = '​SansSerif';​
 +var labelSize ​     = 60;
 +var labelStyle ​    = '​antialiased';​
 +var labelColor ​    = 0;
 +var scaledWidth ​   = 200;
 +var montageColor ​  = 255;
 +var beepDone ​      = true;
 +var tab = '​\t';​
 +var macroDir = getDirectory('​macros'​);​
 +var settingsFileFull = macroDir + settingsFile;​
 +
 +// global variables
 +var inputPath;
 +var outputPath;
 +var folderFormat;​
 +var imageUse1;
 +var image1;
 +var imageUse2;
 +var image2;
 +var imageUse3;
 +var image3;
 +var rowFromChar;​
 +var colFrom;
 +var rowToChar;
 +var colTo;
 +var outputPath;
 +var invertImages;​
 +var invertMontage;​
 +var invertBorders;​
 +var popupDone;
 +var i;
 +var j;
 +var parentDir;
 +var parentParentDir;​
 +var rowFrom;
 +var rowTo;
 +var reportMontage;​
 +
 +
 +//
 +// PlateMontage:​ main program, gets and saves parameters
 +//
 +
 +function PlateMontage() {
 +
 +// default settings
 + inputPath ​     = '​C:​\\AttoVision\\Data\\';​
 + outputPath ​    = '​..\\..\\';​
 + folderFormat ​  = '​384';​
 + imageUse1 ​     = true;
 + image1 ​        = 'Alexa 594 - n000000.tif';​
 + imageUse2 ​     = true;
 + image2 ​        = '​Hoechst - n000000.tif';​
 + imageUse3 ​     = false;
 + image3 ​        = '';​
 + rowFromChar ​   = '​A';​
 + colFrom ​       = 1;
 + rowToChar ​     = '​P';​
 + colTo ​         = 24;
 + invertImages ​  = false;
 + invertMontage ​ = false;
 + invertBorders ​ = false;
 + popupDone ​     = true;
 +
 + rowFrom = charCodeAt(toUpperCase(rowFromChar),​ 0) - 64;
 + rowTo = charCodeAt(toUpperCase(rowToChar),​ 0) - 64;
 +
 +// read settings
 + if (File.exists(settingsFileFull) == 1) {
 + var settings = File.openAsString(settingsFileFull);​
 + var settingLines = split(settings,​ '​\r\n'​);​
 + for (i = 0; i < lengthOf(settingLines);​ i ++) {
 +   setting = split(settingLines[i],​ tab);
 + if (lengthOf(setting) == 1) {
 + var name = setting[0];
 + setting = newArray(2);​
 + setting[0] = name;
 + setting[1] = '';​
 + }
 + if (setting[0] == '​inputPath'​) {
 + inputPath = setting[1];
 + }
 + else if (setting[0] == '​outputPath'​) {
 + outputPath = setting[1];
 + }
 + else if (setting[0] == '​folderFormat'​) {
 + folderFormat = setting[1];
 + }
 + else if (setting[0] == '​imageUse1'​) {
 + imageUse1 = parseInt(setting[1]);​
 + }
 + else if (setting[0] == '​image1'​) {
 + image1 = setting[1];
 + }
 + else if (setting[0] == '​imageUse2'​) {
 + imageUse2 = parseInt(setting[1]);​
 + }
 + else if (setting[0] == '​image2'​) {
 + image2 = setting[1];
 + }
 + else if (setting[0] == '​imageUse3'​) {
 + imageUse3 = parseInt(setting[1]);​
 + }
 + else if (setting[0] == '​image3'​) {
 + image3 = setting[1];
 + }
 + else if (setting[0] == '​rowFromChar'​) {
 + rowFromChar = setting[1];
 + }
 + else if (setting[0] == '​colFrom'​) {
 + colFrom = parseInt(setting[1]);​
 + }
 + else if (setting[0] == '​rowToChar'​) {
 + rowToChar = setting[1];
 + }
 + else if (setting[0] == '​colTo'​) {
 + colTo = parseInt(setting[1]);​
 + }
 + else if (setting[0] == '​scaledWidth'​) {
 + scaledWidth = parseInt(setting[1]);​
 + }
 + else if (setting[0] == '​invertImages'​) {
 + invertImages = parseInt(setting[1]);​
 + }
 + else if (setting[0] == '​invertMontage'​) {
 + invertMontage = parseInt(setting[1]);​
 + }
 + else if (setting[0] == '​invertBorders'​) {
 + invertBorders = parseInt(setting[1]);​
 + }
 + else if (setting[0] == '​popupDone'​) {
 + popupDone = parseInt(setting[1]);​
 + }
 + }
 + }
 + rowFromChar = toUpperCase(rowFromChar);​
 + rowToChar = toUpperCase(rowToChar);​
 + rowFrom = charCodeAt(rowFromChar,​ 0) - 64;
 + rowTo = charCodeAt(rowToChar,​ 0) - 64;
 +
 +// display dialog
 + requires('​1.41j'​);​
 + Dialog.create('​Plate Montage Settings'​);​
 + Dialog.addMessage('​== PlateMontage Macro (Version ' + version + ') ==\n \nCreates a labeled plate montage from BD Pathway plate images\n \nShift-P: Run this macro\nShift-C:​ Close all windows\nShift-M:​ Reload this macro'​);​
 + Dialog.addMessage('​Parent directory of images (DATE-NUMBER;​ leave empty for popup):'​);​
 + Dialog.addString('',​ inputPath, 90);
 + Dialog.addMessage('​Output directory (relative paths: "​.\\"​ (same directory), "​..\\"​ (one up); leave empty for popup):'​);​
 + Dialog.addString('',​ outputPath, 90);
 + Dialog.addMessage('​Image folder format (24: "​A1";​ 96: "​A01",​ 384: "​A001"​):'​);​
 + Dialog.addChoice('',​ newArray('​24',​ '​96',​ '​384'​),​ folderFormat)
 + Dialog.addCheckbox('​Process filename 1 (leave empty for popup):',​ imageUse1);
 + Dialog.addString('',​ image1, 30);
 + Dialog.addCheckbox('​Process filename 2 (leave empty for popup):',​ imageUse2);
 + Dialog.addString('',​ image2, 30);
 + Dialog.addCheckbox('​Process filename 3 (leave empty for popup):',​ imageUse3);
 + Dialog.addString('',​ image3, 30);
 + Dialog.addMessage('​Coordinates of block of wells (non-existing wells will be left empty):'​);​
 + Dialog.addString('​From row:', rowFromChar,​ 1);
 + Dialog.addNumber('​From column:',​ colFrom);
 + Dialog.addString('​To row:', rowToChar, 1);
 + Dialog.addNumber('​To column:',​ colTo);
 + Dialog.addMessage('​Scaled image width in pixels:'​);​
 + Dialog.addNumber('',​ scaledWidth);​
 + Dialog.addCheckbox('​Invert images',​ invertImages);​
 + Dialog.addCheckbox('​Black canvas with white label text', invertMontage);​
 + Dialog.addCheckbox('​Black borders and plate background',​ invertBorders);​
 + Dialog.addMessage(''​);​
 + Dialog.addCheckbox('​Display message when done', popupDone);
 + Dialog.addMessage(''​);​
 + Dialog.show();​
 +
 +// get settings from dialog
 + inputPath ​    = Dialog.getString();​
 + outputPath ​   = Dialog.getString();​
 + folderFormat ​ = Dialog.getChoice();​
 + imageUse1 ​    = Dialog.getCheckbox();​
 + image1 ​       = Dialog.getString();​
 + imageUse2 ​    = Dialog.getCheckbox();​
 + image2 ​       = Dialog.getString();​
 + imageUse3 ​    = Dialog.getCheckbox();​
 + image3 ​       = Dialog.getString();​
 + rowFromChar ​  = Dialog.getString();​
 + colFrom ​      = Dialog.getNumber();​
 + rowToChar ​    = Dialog.getString();​
 + colTo ​        = Dialog.getNumber();​
 + scaledWidth ​  = Dialog.getNumber();​
 + invertImages ​ = Dialog.getCheckbox();​
 + invertMontage = Dialog.getCheckbox();​
 + invertBorders = Dialog.getCheckbox();​
 + popupDone ​    = Dialog.getCheckbox();​
 +
 + rowFromChar = toUpperCase(rowFromChar);​
 + rowToChar = toUpperCase(rowToChar);​
 + rowFrom = charCodeAt(rowFromChar,​ 0) - 64;
 + rowTo = charCodeAt(rowToChar,​ 0) - 64;
 +
 + var processingImages = '';​
 +
 +// ask for image 1
 + if (imageUse2 == true) {
 + if (image2 == ''​) {
 + Popup('​Please select an image 1', 'Image 1');
 + open();
 + image1 = File.getName(File.name);​
 +
 +// get input path from image path
 + if (inputPath == ''​) {
 + inputPath = replace(File.directory,​ '​\\.*?​\\.*?​$',​ '​\\'​);​
 + }
 + close();
 + }
 + processingImages = processingImages + image1 + '​\n';​
 + }
 +
 +// ask for image 2
 + if (imageUse2 == true) {
 + if (image2 == ''​) {
 + Popup('​Please select an image 2', 'Image 2');
 + open();
 + image2 = File.getName(File.name);​
 +
 +// get input path from image path
 + if (inputPath == ''​) {
 + inputPath = replace(File.directory,​ '​\\.*?​\\.*?​$',​ '​\\'​);​
 + }
 + close();
 + }
 + processingImages = processingImages + image2 + '​\n';​
 + }
 +
 +// ask for image 3
 + if (imageUse3 == true) {
 + if (image3 == ''​) {
 + Popup('​Please select an image 3', 'Image 3');
 + open();
 + image3 = File.getName(File.name);​
 +
 +// get input path from image path
 + if (inputPath == ''​) {
 + inputPath = replace(File.directory,​ '​\\.*?​\\.*?​$',​ '​\\'​);​
 + }
 + close();
 + }
 + processingImages = processingImages + image3 + '​\n';​
 + }
 +
 +// select input path
 + if (inputPath == ''​) {
 + inputPath = getDirectory('​Parent directory (DATE-NUMBER)'​);​
 + }
 +
 +// add trailing \
 + inputPath = replace(inputPath,​ '​([^\\\\])$',​ '​$1\\\\'​);​
 +
 +// select output path
 + if (outputPath == ''​) {
 + outputPath = getDirectory('​Output directory'​);​
 + }
 +
 +// add trailing \
 + outputPath = replace(outputPath,​ '​([^\\\\])$',​ '​$1\\\\'​);​
 +
 +// save settings to file
 + var file = File.open(settingsFileFull) ;
 + print(file,​ '​inputPath' ​    + tab + inputPath);
 + print(file,​ '​outputPath' ​   + tab + outputPath);​
 + print(file,​ '​folderFormat' ​ + tab + folderFormat);​
 + print(file,​ '​imageUse1' ​    + tab + imageUse1);
 + print(file,​ '​image1' ​       + tab + image1);
 + print(file,​ '​imageUse2' ​    + tab + imageUse2);
 + print(file,​ '​image2' ​       + tab + image2);
 + print(file,​ '​imageUse3' ​    + tab + imageUse3);
 + print(file,​ '​image3' ​       + tab + image3);
 + print(file,​ '​rowFromChar' ​  + tab + rowFromChar);​
 + print(file,​ '​colFrom' ​      + tab + colFrom);
 + print(file,​ '​rowToChar' ​    + tab + rowToChar);
 + print(file,​ '​colTo' ​        + tab + colTo);
 + print(file,​ '​scaledWidth' ​  + tab + scaledWidth);​
 + print(file,​ '​invertImages' ​ + tab + invertImages);​
 + print(file,​ '​invertMontage'​ + tab + invertMontage);​
 + print(file,​ '​invertBorders'​ + tab + invertBorders);​
 + print(file,​ '​popupDone' ​    + tab + popupDone);
 + File.close(file);​
 +
 +// convert relative o absolute output path
 + if (matches(outputPath,​ '​^(\\.|\\.\\.)\\\\.*?​$'​) == true) {
 + outputPath = inputPath + outputPath;
 + var outputPathOld;​
 + do {
 + outputPathOld = outputPath;
 + outputPath = replace(outputPath,​ '​\\\\\\.\\\\',​ '​\\\\'​);​
 + outputPath = replace(outputPath,​ '​\\\\[^\\\\]+\\\\\\.\\.\\\\',​ '​\\\\'​);​
 + } while (outputPath != outputPathOld);​
 + }
 +
 +// check values
 + if (rowFrom < 1) {
 + exit('​Start row ' + rowFromChar + ' is not between A and P');
 + }
 + if (rowTo > 16) {
 + exit('​End row ' + rowToChar + ' is not between A and P');
 + }
 + if (rowFrom > rowTo) {
 + exit('​End row ' + rowToChar + ' is smaller than start row ' + rowFromChar);​
 + }
 +
 + if (colFrom < 1) {
 + exit('​Start column ' + colFrom + ' is not between 1 and 24');
 + }
 + if (colTo > 24) {
 + exit('​End col ' + colTo + ' is not between 1 and 24');
 + }
 + if (colFrom > colTo) {
 + exit('​End column ' + colTo + ' is smaller than start column ' + colFrom);
 + }
 +
 +// check paths
 + if (File.isDirectory(inputPath) == false) {
 + exit('​Parent directory "'​ + inputPath + '"​ does not exist'​);​
 + }
 + if (File.isDirectory(outputPath) == false) {
 + exit('​Output directory "'​ + outputPath + '"​ does not exist'​);​
 + }
 +
 +// process images
 + CloseImages();​
 +
 +// get name of parent directories
 + parentDir = replace(inputPath,​ '​^.*?​\\\\([^\\\\]*?​)\\\\$',​ '​$1'​);​
 + parentParentDir = replace(inputPath,​ '​^.*?​\\\\([^\\\\]*?​)\\\\[^\\\\]*?​\\\\$',​ '​$1'​);​
 + reportMontage = '';​
 +
 +// print to log
 + print('​Processing...\nDirectory:​ ' + parentParentDir + '​\\'​ + parentDir + '​\nPath:​ ' + inputPath + '​\nImages:​\n'​ + processingImages);​
 + ProcessMontage(image1,​ imageUse1);
 + ProcessMontage(image2,​ imageUse2);
 + ProcessMontage(image3,​ imageUse3);
 +
 +// print to log
 + print('​Output path: ' + outputPath + '​\nMontage files: ' + reportMontage + '​\nDone!\n--------\n'​);​
 +
 +// beep
 + if (beepDone == true) {
 + beep();
 + }
 +
 +// popup
 + if (popupDone == true) {
 + Popup('​Done!\n \nSaved to: \n' + outputPath + '\n \nMontage files:'​ + reportMontage,​ '​Done'​);​
 + }
 +
 + return;
 +}
 +
 +
 +//
 +// ProcessMontage:​ create and save a montage
 +//
 +
 +function ProcessMontage(image,​ imageUse) {
 +
 + if (imageUse == true) {
 +
 +// create montage file name
 + var montageImage = parentParentDir + ', ' + parentDir + ', ' + replace(image,​ '​\\.\\w+$',​ ''​) + '​.png';​
 + CreateMontage(image,​ montageImage);​
 + if (isOpen(montageImage)) {
 + reportMontage = reportMontage + '​\n'​ + montageImage;​
 + selectWindow(montageImage);​
 + saveAs('​PNG',​ outputPath + montageImage);​
 + }
 + if (isOpen('​Log'​)) {
 + selectWindow('​Log'​);​
 + }
 + }
 + return;
 +}
 +
 +
 +//
 +// CreateMontage:​ create a montage
 +//
 +
 +function CreateMontage(image,​ montageImage) {
 +
 + if (isOpen('​Log'​)) {
 + selectWindow('​Log'​);​
 + }
 + setBatchMode(true);​
 +
 + // image folder name format
 + var folderDigits = '​000';​
 + if (folderFormat == '​24'​) {
 + folderDigits = '​0';​
 + }
 + if (folderFormat == '​96'​) {
 + folderDigits = '​00';​
 + }
 + else if (folderFormat == '​384'​) {
 + folderDigits = '​000';​
 + }
 +
 + var scalingFactor;​
 + var dimensionsCreated = false;
 + var montageCreated = false;
 +
 + var numRows = rowTo - rowFrom + 1;
 + var numCols = colTo - colFrom + 1;
 +
 +// cycle through images
 + for (row = 0; row < numRows; row ++) {
 + var rowNumber = row + rowFrom;
 + var rowChar = fromCharCode(rowNumber + 64);
 +
 + for (col = 0; col < numCols; col ++) {
 + var colNumber = col + colFrom;
 + var colStr = substring(folderDigits,​ lengthOf(toString(colNumber))) + colNumber;
 +
 +// open image
 + var imageFileFull = inputPath + 'Well ' + rowChar + colStr + '​\\'​ + image;
 + if (File.exists(imageFileFull) == true) {
 + open(imageFileFull);​
 + rename('​Image'​);​
 +
 +// get dimensions from first image
 + if (dimensionsCreated == false) {
 + dimensionsCreated = true;
 + var width = getWidth();
 + var height = getHeight();​
 + scalingFactor = scaledWidth / width;
 + scaledHeight = floor(height * scalingFactor);​
 + }
 +
 +// create montage with dimensions
 + if (montageCreated == false) {
 + montageCreated = true;
 + montageWidth = labelWidth * 2 + scaledWidth * numCols + borderWidth * (numCols + 1);
 + montageHeight = labelHeight + scaledHeight * numRows + borderWidth * (numRows + 1);
 + newImage(montageImage,​ '​16-bit Black' + montageColor,​ montageWidth,​ montageHeight,​ 1);
 + setForegroundColor(255,​ 255, 255);
 + run('​Select All');
 + run('​Fill'​);​
 +
 +// label montage
 + setFont(labelFont,​ labelSize, labelStyle);​
 + setColor(labelColor);​
 + setJustification('​center'​);​
 +
 +// label columns
 + var x = scaledWidth / 2 + labelWidth * 2 + borderWidth;​
 + var y = labelHeight - 10;
 + for (colNumberLabel = colFrom; colNumberLabel <= colTo; colNumberLabel ++) {
 + drawString(colNumberLabel,​ x, y);
 + x += scaledWidth + borderWidth;​
 + }
 +
 +// label rows
 + var x1 = labelWidth / 2;
 + var x2 = labelWidth / 2 + labelWidth;
 + var y = labelHeight + borderWidth + scaledHeight / 2 + 30;
 + for (rowNumberLabel = rowFrom; rowNumberLabel <= rowTo; rowNumberLabel ++) {
 + var rowCharLabel = fromCharCode(rowNumberLabel + 64);
 + drawString(rowNumberLabel,​ x1, y);
 + drawString(rowCharLabel,​ x2, y);
 + y += scaledHeight + borderWidth;​
 + }
 +
 +//invert
 + if ( (invertMontage == true) || (invertBorders == true) ) {
 + makeRectangle(labelWidth * 2, labelHeight,​ montageWidth - labelWidth * 2, montageHeight - labelHeight);​
 +
 +// invert border and image background
 + if (invertBorders == true) {
 + run('​Invert'​);​
 + }
 +
 +// invert montage background and labels
 + if (invertMontage == true) {
 + run('​Make Inverse'​);​
 + run('​Invert'​);​
 + }
 +
 + run('​Select None'​);​
 + }
 + }
 +
 +// scale image
 + selectWindow('​Image'​);​
 + run('​Scale...',​ 'x=- y=- width='​ + scaledWidth + ' height='​ + scaledHeight + ' interpolate title=[Image]'​);​
 + run('​Canvas Size...',​ '​width='​ + scaledWidth + ' height='​ + scaledHeight + ' position=Center'​);​
 + run('​Multiply...',​ '​value=16'​);​
 +
 +// invert
 + if (invertImages == true) {
 + run('​XOR...',​ '​value=1111111111111111'​);​
 + }
 +
 +// copy scaled image into montage
 + selectWindow('​Image'​);​
 + run('​Select All');
 + run('​Copy'​);​
 + selectWindow(montageImage);​
 + makeRectangle(labelWidth * 2 + scaledWidth * col + borderWidth * (col + 1), labelHeight + scaledHeight * row + borderWidth * (row + 1), scaledWidth,​ scaledHeight);​
 + run('​Paste'​);​
 + run('​Select None'​);​
 + selectWindow('​Image'​);​
 + close();​
 + }
 + }
 +  }
 +
 + selectWindow(montageImage);​
 + setBatchMode(false);​
 +
 + return;
 +}
 +
 +
 +//
 +// Popup: popup a message
 +//
 +
 +function Popup(text, title) {
 + text = ''​ + text;
 + title = ''​ + title;
 + Dialog.create(title);​
 + Dialog.addMessage(text)
 + Dialog.show();​
 + return;
 +}
 +
 +
 +//
 +// CloseAllImages
 +//
 +
 +function CloseImages() {
 +
 + for (i = nImages(); i > 0; i -- ) {
 + selectImage(i);​
 + close();
 + }
 + return;
 +}
 +
 +
 +//
 +// CloseAllImages
 +//
 +
 +function CloseAllImages() {
 +
 + CloseImages();​
 +
 +// close message window
 + if (isOpen('​Log'​)) {
 + selectWindow('​Log'​);​
 +    run('​Close'​);​
 + }
 +
 + return;
 +}
 +
 +
 +// install macro: plate montage
 +macro 'Plate Montage [P]' {
 + PlateMontage();​
 +}
 +
 +// install macro: reload the macro
 +macro '​Reload Plate Montage macro [M]' {
 + run('​Install...',​ '​install=[C:​\\Program Files\\ImageJ\\macros\\PlateMontage.ijm]'​);​
 +}
 +
 +// install macro: close all images
 +macro 'Close all images [C]' {
 + CloseAllImages();​
 +}
 +</​code>​
macro/platemontage.txt ยท Last modified: 2019/04/12 11:13 (external edit)