Batch merging macro on Fiji

Hello, I am new at macro coding on Fiji and I am trying to batch merge a list of images that are separated in single channels. The structure of the file name is the following

scan_Plate_TR_p00_0_A01f00d0
scan_Plate_TR_p00_0_A01f00d3
scan_Plate_TR_p00_0_A02f00d0
scan_Plate_TR_p00_0_A02f00d3

My goal is to

  1. Select only those images containing the string TR
  2. merge the channels (d0 and d3) for each well (A01, A02, etc)
  3. Save as .tiff

When I run the code below I get the following error:
image

dir1 = getDirectory("Choose Source Directory");
dir2 = getDirectory("Choose Destination Directory");

list = getFileList(dir1);
Array.sort(list);
setBatchMode(true);

for(i=0;i<list.length;i++){ 
	if((startsWith(list[i],"scan_Plate_TR")) && (endsWith(list[i],"00d1"))){ 
      blue = Array.concat(list[i]); 
  } 
}
for(i=0;i<list.length;i++){ 
  	if(startsWith(list[i],"scan_Plate_TR") && (endsWith(list[i], "00d3"))){ 
      gray = Array.concat(list[i]); 
  } 
}

  run("Merge Channels...", "c3="+ blue[f] +" c4=" + gray[f] + "create");
  saveAs("tiff", dir2 + fileName + "_Composite");
  close();
}
print("done"); 

Any help is much appreciated, thanks!

Pasquale

I only took a quick look, but I do not see that “f” is defined anywhere.

Thanks, I have modified it and defined f in a for loop. I still get the same error, sorry I am a bit lost.

dir1 = getDirectory("Choose Source Directory");
dir2 = getDirectory("Choose Destination Directory");

list = getFileList(dir1);
Array.sort(list)
setBatchMode(true);

for(i=0;i<list.length;i++){ 
	if((startsWith(list[i],"scan_Plate_TR")) && (endsWith(list[i],"00d1"))){ 
      blue = newArray(list[i]);
  } 
}
for(i=0;i<list.length;i++){ 
  	if(startsWith(list[i],"scan_Plate_TR") && (endsWith(list[i], "00d3"))){ 
      gray = newArray(list[i]);
  } 
}

for(f=1;f<blue.length;f++){ 
  open(dir1+blue[f]);
  run("Enhance Contrast", "saturated=0.35");
  run("Apply LUT");
  open(dir1+gray[f]);
  run("Enhance Contrast", "saturated=0.35");
  run("Apply LUT");
  run("Merge Channels...", "c3="+ blue[f] +" c4=" + gray[f] + " create");
  dotIndex = indexOf(blue[f],'.');
  fileName = substring(blue[f], 0, dotIndex);
  saveAs("tiff", dir2 + fileName + "_Composite");
  close();
} 

Could this be because blue is empty? You want to merge files ending with “00d0” but your code seeks “00d1”.
It may help to copy the debug window

M.

The cause of the error is the variable “blue” (the angle brackets in the error message highlight the undefined variable: <blue>). It is conditionally (!) defined in your first for-loop:

for (...) {
   if (startsWith...) {
      blue = ...
   }
}

If the condition is not met (if the first file does not start with “scan_Plate…”), then the array “blue” is not created and the call on “blue” yields a null pointer exception in the third for-loop.

You have to create nested for-loops, packing the final one (for f=1; f<blue.length…) into the first loop. Alternatively, wrap the final for-loop into a function and call it from within the first one.

Best,
Thomas

Hi Thomas, thanks for the explanation. Don’t I need also the second for loop before I run the 3rd? If I nest the 3rd in the 1st then I guess it won’t recognize the “gray” variable.

Also, I am a bit confused about the conditional definition of “blue”, the directory includes many files that do not start with “scan_Plate_TR”. My understanding is that the for loop iterate through all the files of that folder until it finds the first that matches the startWith argument and then it creates the “blue” array. Please correct me if I am wrong.

There are more bugs in your code, with the prime one being the Array.concat() command. It expects two arguments, not just one as in your macro. Anyway, I have re-written the whole thing and added a few comments to the code:


dir1 = getDirectory("Source");
dir2 = getDirectory("Destination");

list = getFileList(dir1);
Array.sort(list);
setBatchMode(true);

// Create the arrays first
blue = newArray(0);
gray = newArray(0);

// Get the blue and gray channel names
for (i = 0; i < list.length; i++) {
   file = list[i];
   if (startsWith(file, "scan_Plate_TR")) {
      if (endsWith(file, "00d0")) {
         blue = Array.concat(blue, file); 
      } else if (endsWith(file, "00d3")) { 
         gray = Array.concat(gray, file); 
      }
   } 
}

// A safeguard. If one channel image is missing, we would fail somewhere
if (blue.length != gray.length) {
   exit("Unequal number of blue and gray channels found");
}

// Loop over the images
for (i = 0; i < blue.length; i++) {
   blueChannel = blue[i];
   grayChannel = gray[i];
   open(dir1+blueChannel);
   enhance(getImageID());
   open(dir1+grayChannel);
   enhance(getImageID());
   // Using the "&" string expansion option within command arguments
   run("Merge Channels...", "c3=&blueChannel c4=&grayChannel create");
   fileName = substring(blueChannel, 0, lastIndexOf(blueChannel, "00d0"))+"_Composite";
   saveAs("tiff", dir2 + fileName);
   close();
}

// All common image processing tasks in here
function enhance(imageID) {
   selectImage(imageID);
   run("Enhance Contrast", "saturated=0.35");
   run("Apply LUT");
}

setBatchMode(false);
print("Done");
3 Likes

Hi Thomas, thank you for your help. the code makes more sense now :slight_smile:
I have tried it but for some reason it does nothing. It seems that it runs till the end because it prints done but it doesn’t output anything and it doesn’t throw any error either.

I’ve attached a screenshot of the files in the input folder.

For testing, I created an input folder “src”, an output folder “dst”, and added a few empty dummy TIFFs to the src folder. Upon running the macro, I obtain the following directory content:

The macro did what it is supposed to do: it silently loads the images (without showing them), since it runs in batch mode. In line 6 of the macro:

setBatchMode(true);

It merges the channels, saves them with the extension _Composite.tif in the “dst” folder, then closes the image without ever having shown anything on screen. Finally, it exits the batch mode (if you leave it in batch mode, it will never show you any image). Line 50:

setBatchMode(false);
print("Done");

If you want to see it in action, change the batch mode command in line 6 to:

setBatchMode(false);

For debugging, you can also add print statements wherever you want. For example after an “open(path)” command:

print("Now I opened "+getTitle()); //prints the title of the active window in the log window

It’s very strange because when I switch the setBatchMode to false in line 6 it doesn’t pop up the images so I guess the problem is more upstream, opening these files…
I’ve tried to use the print after the open(path) and nothing happens.

One can exhaustively make use of the print() command to see how far the macro runs and what the value of variables are, at any line of the macro. For example, you can check the size of the arrays “blue” and “gray”, to see how many images the first for-loop has picked up:

print("Blue channel images: "+blue.length);

If the array size is 0, it will not do anything in the main for-loop, and the error must be somewhere in or already before the first for-loop.

Hi Thomas, thanks. I think the reason it wasn’t working was that windows hides the file extensions. I have used “File.getNameWithoutExtension(path)” function to get the filename without the extension. Then it gets passed to the endsWith function instead of the full filename.