("C:\Users\Desktop\Images") in Script (instead of getDirectory) for folders

script
scripting
macro
Tags: #<Tag:0x00007fb882da71d0> #<Tag:0x00007fb882da6f78> #<Tag:0x00007fb882da6cd0>

#1

Hi ImageJ Forum,

I have been working on a Script that prompts the user to select directories (getDirectory) around 15 times before it finishes. I would like to include the folder location (C:\Users…) into the script so the folder is automatically chosen, instead of getDirectory’s prompt to choose.

I have been exploring ways to do this but am getting an error that searches have not cleared-up. I have uploaded an image of what I have so far.

Thanks in advance,

-Michael


#2

Hi @Michael,

From the screenshot I can see a couple of potential issues:

  • the open command doesn’t include a backslash between directory and file name (this is corroborated by the error message-- look at the name of the file it’s trying to open)
  • the saveAs() command includes a forward slash rather than a backslash.

If you really want to hard-code the directories, just correct these issues and it should work.

However, I’d recommend trying Script Parameters which give you the best of both worlds – you can allow the user to select the input and output directories once at the beginning of the run, using a tidy dialog.

For examples of how to use script parameters and the resulting path names, look at the “IJ1 macro” templates in the Fiji Script Editor.

Hope this helps.


#3

Hi @tswayne,

Thank you for your help.

I am trying to open the directory to process multiple images. I am currently achieving this by using the getDirectory option to select a directory for processing.

Here is a section of the script:

setBatchMode(true);
inputDir1 = getDirectory("Select folder 1 - DAPI IN "); 
outputDir = getDirectory("Select folder 2 - DAPI OUT "); 
fileList1 = getFileList(inputDir1); 
for (i = 0; i < fileList1.length; i++) { 
  file1 = fileList1[i]; 
  open(inputDir1+file1); 
setAutoThreshold("Default dark");
//run("Threshold...");
setThreshold(80, 254);
setOption("BlackBackground", false);
run("Convert to Mask");
run("Analyze Particles...", "size=200-1700 circularity=0.35-1.00 show=Masks exclude clear in_situ");
run("Fill Holes");
  outName = File.getName(file1); 
  saveAs("Tiff", outputDir + "/" + outName); 
} 

This is currently working great as it is and my approach in hard-coding the directory may be clumsy.

Is there better approach to hard-code these directories?

I would eventually like to include Script Parameters into my understanding but I am still wrapping my head around basic scripting.

Thanks for your help,

-Michael


#4

Hi @Michael,

Below is your processing code plugged into the Batch Processing macro template (Templates menu in the Fiji Script Editor).

(In the forum, adding 3 backticks before and after the code gives you a more readable format)

The Script Parameters are simply the lines at the top that collect the directory names and file suffix from the user at the beginning. IMO this is the best way to get a properly formatted directory name at the beginning of a script.

#@ File (label = "Select folder 1 - DAPI IN", style = "directory") input
#@ File (label = "Select folder 2 - DAPI OUT ", style = "directory") output
#@ String (label = "File suffix", value = ".tif") suffix

setBatchMode(true);
processFolder(input);

// function to scan folders/subfolders/files to find files with correct suffix
function processFolder(input) {
   list = getFileList(input);
   list = Array.sort(list);
   for (i = 0; i < list.length; i++) {
   	if(File.isDirectory(input + File.separator + list[i]))
   		processFolder(input + File.separator + list[i]);
   	if(endsWith(list[i], suffix))
   		processFile(input, output, list[i]);
   }
}

function processFile(input, output, file) {

   open(input + File.separator + file);
   setAutoThreshold("Default dark");
   //run("Threshold…");
   setThreshold(80, 254);
   setOption("BlackBackground", false);
   run("Convert to Mask");
   run("Analyze Particles...", "size=200-1700 circularity=0.35-1.00 show=Masks exclude clear in_situ");
   run("Fill Holes");
   saveAs("Tiff", output + File.separator + file);
   print("Processing: " + input + File.separator + file);
   print("Saving to: " + output);

}

Hope this helps.


#5

Thank you @tswayne!

This has been a huge help in the right direction. I really like the setup of with Parameters. I am able to establish all directories and associate them to be called upon later. Awesome.

I have deleted the remainder of the original message because the next post makes much more sense, in terms of code, and to reduce redundancy in the thread.

Thanks,

-Michael


#6

Hi @tswayne,

I have been trying to figure this out and I feel I am getting closer, if I understand this right.

The original process was a series of macros that process a bunch of images from folder 1 to folder 2. Then the next macro in the script took images from folder 2 and folder 3 to use with image calculator and save in folder 4. Previously, this was done along with 8 other folders using the getDirectory command in a single script.

I have noticed from experimenting with Script Parameters that my code is not saving the first group of commands into folder 2. This is required because then next part uses those images with image calculator.

Here is the code so far:

#@ File (label = "Select folder 1 - DAPI IN", style = "directory") folder_1
#@ File (label = "Select folder 2 - DAPI OUT ", style = "directory") folder_2
#@ String (label = "File suffix", value = ".tif") suffix

setBatchMode(true);
processFolder(folder_1);

// function to scan folders/subfolders/files to find files with correct suffix
function processFolder(folder_1) {
   list = getFileList(folder_1);
   list = Array.sort(list);
   for (i = 0; i < list.length; i++) {
   	if(File.isDirectory(folder_1 + File.separator + list[i]))
   		processFolder(folder_1 + File.separator + list[i]);
   	if(endsWith(list[i], suffix))
   		processFile(folder_1, folder_2, list[i]);
   }
}

function processFile(folder_1, folder_2, file) {

   open(folder_1 + File.separator + file);
   setAutoThreshold("Default dark");
   //run("Threshold…");
   setThreshold(80, 254);
   setOption("BlackBackground", false);
   run("Convert to Mask");
   run("Analyze Particles...", "size=200-1700 circularity=0.35-1.00 show=Masks exclude clear in_situ");
   run("Fill Holes");
   saveAs("Tiff", folder_2 + File.separator + file);

}


#@ File (label = "Select folder 2 - DAPI OUT ", style = "directory") folder_2
#@ File (label = "Select folder 3 - NeuN", style = "directory") folder_3
#@ File (label = "Select folder 4 - Nuclear Holes ", style = "directory") folder_4
#@ String (label = "File suffix", value = ".tif") suffix

setBatchMode(true);
processFolder(folder_2);

// function to scan folders/subfolders/files to find files with correct suffix
function processFolder(folder_2) {
   list = getFileList(folder_2);
   list = getFileList(folder_3);
   list = Array.sort(list);
   for (i = 0; i < list.length; i++) {
   	if(File.isDirectory(folder_2 + File.separator + list[i]))
   		processFolder(folder_2 + File.separator + list[i]);
   	if(endsWith(list[i], suffix))
   		processFile(folder_2, folder_3, list[i]);
   }
}


function processFile(folder_2, folder_3, file) {

   open(folder_2 + File.separator + file);
   id1 =getImageID()
   open(folder_3 + File.separator + file);
   id2 =getImageID()   
   imageCalculator("Subtract ", id2, id1); 
   saveAs("Tiff", folder_4 + File.separator + file);
   print("Processing: " + folder_2 + File.separator + file);
   print("Saving to: " + folder_4);

}

When I Run, I get this error:

error

The images in folder 1 are DAPI images and the images in folder 3 are NeuN images.

The script is currently not saving the DAPI images in folder 2 and not recognizing the NeuN images in folder 3.



05/13/18 Update:

If I copy your modified example code into ImageJ then it will process images from folder 1 to folder 2, as I want. But if I have further code that intends to use those images saved in folder 2 to combine with folder 3 in image calculator then save to folder 4 then it does not save any images to folder 2.

The way my process works is by modifying images, saving them to folders, recalling those folders (with modified images), repeating with adjusted settings, then ultimately combining them into seed images for CellProfiler.

I was able to achieve this using the getDirectory command about 12 times throughout the Script, but that is laborious. So I originally thought I could easily hard-code the directories, which I could not achieve. But your suggestion to use Script Parameters sounds like a much better option because then I will not have to change the code every time I use a different computer. I like that it establishes all of the directories, associated by a keyword (input1, input2, input3, output, ect), that called be called upon later in the code as needed. At one point I do merge three different folders with run(merge) and save into a 4th.

I am not sure of the fundamentals behind how Script Parameters is different than the earlier non-parameters version.

So I believe my main problem now that I can get the first part of the code to save to folder 2 (your post) but if I copy that and make adjustments to then sequentially take those images saved into folder 2, from previous section of macro, process, and save into a third folder then is no longer saves them into folder 2 and instead it processes and saves to the third folder.

I need to it process, save, recall, process, recall multiple inputs, save, ect in one script with predefined inputs and outputs with Parameters.

I have been searching, learning, scouring the Macro Functions page for options but I am getting nowhere.

-Michael


#7

Hi @Michael,

Good to see the progress! A couple more suggestions:

About script parameters:
Script parameters only work at the very beginning of a script/macro, because they are interpreted by a different “machinery.” This is ultimately a good thing because you can re-use the same code in many languages. Search the imagej.net wiki and this forum to find technical details from actual professional programmers :slight_smile: .

What to do: Move all your script parameters to the beginning of the macro.

About the macro structure:
It might help to take a step back and convince yourself of how the “batch process” template works. I admit it took me a while to get what this code was doing, when I was first learning to write macros. The introduction to macro programming may help – especially the section on functions.

For any batch process you need to define the functions that are going to do the work, and then call the functions to actually do the work.

In your code above, processFile() and processFolder() are functions that are defined twice with different bodies. This won’t work! AFAIK the 2nd definition will not be seen by the macro interpreter. To do different operations, define different functions.

What to do:

  • Trace your way through the batch template (or my version above) to see how it processes all the files in a folder. Add print statements, write it out on paper, whatever it takes to get it.

  • Figure out how what functions you need to do your processing tasks. It sounds like you probably need 2 folder processors and 2 file processors. But maybe there is a more efficient way to do it.

  • Figure out what your main code is going to be. This is the part where you actually call the folder processing function(s) you defined earlier. In the batch template, this section is only 2 lines long. Yours won’t be much longer.

  • If you still have problems, add print statements to help understand what is happening in the code and where things go wrong.

Good luck!


#8

Hi @tswayne,

Thank you for the explanations and direction! I will make time in the next few weeks to read the basics with an emphasis on functions. It is challenging to learn which letters/symbols are part of the basic operation so I can see a better understanding of that will shed the light that I need.

After I have taken time to learn more, if I have questions then I will start a new thread
about the specific question.

Thanks again for your time and help!

-Michael