Save A File With The Name Of Its Directory

Hi everyone,
First of all, I’d like to thank all of you for partaking to this wonderful collaborative experience. You girls/guys prove that collaboration is more powerful than competition and I can’t thank you enough for that. We need more of this, especially within the academic world.

Now let’s get back to work…

I am a pure noob in the world of macros, so let me explain what I am trying to do:

  • all my images have the same name (eg. C0001.tif)
  • each image is located in a different directory (eg. Mol1_Date1; Mol1_Date2; Mol2_Date1; Mol2_Date2)

=> I’d like to open the images only located in the directories containing “Mol1” in their name/path.

=> then I’d like to save a copy of each with the name of their own directory, within their own directory… (does it make sense for anyone so far?)

  • now I should have several .tif files* like Mol1_Date1.tif; Mol1_Date2.tif in their respective directory.

=> finally, I’d like to run the macros I recorded on every .tif files containing Mol1 in their name


Here is the 1st macro I use. It is very simple and I think I’ll be good for the other processes/macros I wanna run.

open("C:\\path\\image.tif");
call("ij.ImagePlus.setDefault16bitRange", 16);
run("Appearance...", "antialiased menu=15 16-bit=[16-bit (0-65535)]");16); 
run("Set Measurements...", "area mean min area_fraction display redirect=None decimal=3");16);
run("Properties...", "channels=1 slices=1 frames=1 unit=pixel pixel_width=1 pixel_height=1 16);
voxel_depth=1 global");16);
run("Measure");16);
close();

Thank you all for your kindness and your time.

Best regards

Hi @Moximatoz

Thanks for the kind words at the start… another reason I love this community. :slight_smile:

Just to get you a start - though I’m sure someone on here will be able to provide you a more concrete solution - have a look at the following code example:

// @File(label = "Input directory", style = "directory") input
// @File(label = "Output directory", style = "directory") output
// @String(label = "File suffix", value = ".tif") suffix

/*
 * Macro template to process multiple images in a folder
 */

// See also Process_Folder.py for a version of this code
// in the Python scripting language.

processFolder(input);

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

function processFile(input, output, file) {
	// Do the processing here by adding your own code.
	// Leave the print statements until things work, then remove them.
	print("Processing: " + input + file);
	print("Saving to: " + output);
}

You can find this in the Script EditorTemplates > ImageJ 1.x > Examples > Process Folder (IJ1 Macro).

I was getting a little lost in your descriptions … but I think this sample code might help you figure it all out. You have a solid enough base to get things working with this example I should think.

Hope it helps!

eta :slight_smile:

4 Likes

Thank you for your quick answer.

Because I was focused on trying to figure this thing out all day I didn"t even see you post…

But I’m on something that is close I think, so I’ll come back very soon for an update on the situation.

Salute!

1 Like

Hi Moximatoz,

I spotted your question yesterday and @etadobson’s response providing that excellent resource/example. As I haven’t tried that kind of file processing before I wanted to practice and came up with this:

keyword = "Mol1";
filename = "C0001.tif"
input = getDirectory("Choose a Directory")
//output = 
processFolder(input);

// function to scan folders/subfolders/files to find files with correct suffix
function processFolder(input) {
	list = getFileList(input);
	for (i = 0; i < list.length; i++) {
		if(File.isDirectory(input + list[i]))
			processFolder("" + input + list[i]);
		if(File.isDirectory(input + list[i]) && (matches(list[i], ".*"+keyword+".*")))
			processFolderKeyword("" + input + list[i]);
			//processFile(input, output, list[i]);
	}
}

function processFolderKeyword(input) {
	list = getFileList(input);
	for (j = 0; j < list.length; j++) {
		if(File.isDirectory(input + list[j]))
			processFolder("" + input + list[j]);
		if(File.isDirectory(input + list[j]) && (matches(list[j], ".*"+keyword+".*")))
			processFolderKeyword("" + input + list[j]);
			processFile(input, list[j]);
			//processFile(input, output, list[j]);
	}
}

//function processFile(input, output, file) {
function processFile(input, listname) {
	// Do the processing here by adding your own code.
	// Leave the print statements until things work, then remove them.
	if(matches(listname, filename))
		print("Processing: " + input + listname);
		//print("Saving to: " + output);
}

Just the file processing and saving bit that I left out (currently just printing the file name and path). Also, as the macro currently works, the first user-chosen directory will not have “C0001.tif” files processed from within it directly; only from within folders and sub-folders of the chosen directory.

Kind regards.

2 Likes

Oops,

sorry I didn’t test this properly. There’s at least one error with the above code.
Please replace the ‘processFolderKeyword’ function with:

function processFolderKeyword(input) {
	list = getFileList(input);
	for (j = 0; j < list.length; j++) {
			processFile(input, list[j]);
			//processFile(input, output, list[j]);
	}
}

Regards.

Hi there,

I am trying to do something similar, but I want to create a folder and save the processed images there for every sub-folder, in what part of the script do it to insert that function?
Any help will be appreciated.

Regards.

Ed

Hi Ed,

Where you put the code to create a directory depends on whether you want the images all saved to one folder or to many new folders. If you want the macro to process all images and to save them all to a single folder, then its not a bad idea to define and create that location at the beginning of the macro. Using the existing macro as an example, something like this:

keyword = "Mol1";
filename = "C0001.tif"
input = getDirectory("Choose a Directory")
output = getDirectory("home") + "Desktop";
replicate = 1;
File.makeDirectory(output + File.separator + "New_Folder");
processFolder(input);

Which will create a new directory entitled “New_Folder” on the user’s desktop.

Then in the ‘processFile’ function, its simply a matter of saving the (un)modified image(s) to this location. Something like this:

function processFile(input4, listname) {
	// Do the processing here by adding your own code.
	// Leave the print statements until things work, then remove them.
	if(matches(listname, filename))
		//setBatchMode(true);
		open(input4 + listname);
		save(""+ output + File.separator + "New_Folder" + File.separator + replicate + " " + listname);
		replicate++;
		close();
		//setBatchMode(false);
}

The ‘replicate’ variable is just something I added to allow multiple of the same named file to be saved to the same location. Also why I set it to 1 at the very beginning of the macro.

Now… if you want a new folder to be created after the processing of each image, then the ‘File.makeDirectory()’ command should be moved to within the ‘processFile’ function.

Hope that helps.

1 Like

Thank you all for your help, I am amazed to realize how little I understand your macros, hehe.

Regarding my issue, I figured out this macro which opens a file and saves it with the name of its own directory. It works automatically when I open the macro and run it, if the path is correct:

setBatchMode(true);
open("C:\\path\\s_C001.tif");
dir=getDirectory("image"); 
name = File.getName(dir); 
saveAs("tiff", File.directory+name);
close()
setBatchMode(false);

Unfortunately I can’t figure out how to automate and batch process this with multiple directories and multiple images, using keyword A to select specific directories and keyword B for specific images.

I tried modifying the built-in macro “BatchProcessFolders.txt” which does this:

// "BatchProcessFolders"
//
// This macro batch processes all the files in a folder and any
// subfolders in that folder. In this example, it runs the Subtract 
// Background command of TIFF files. For other kinds of processing,
// edit the processFile() function at the end of this macro.

   requires("1.33s"); 
   dir = getDirectory("Choose a Directory ");
   setBatchMode(true);
   count = 0;
   countFiles(dir);
   n = 0;
   processFiles(dir);
   //print(count+" files processed");
   
   function countFiles(dir) {
      list = getFileList(dir);
      for (i=0; i<list.length; i++) {
          if (endsWith(list[i], "/"))
              countFiles(""+dir+list[i]);
          else
              count++;
      }
  }

   function processFiles(dir) {
      list = getFileList(dir);
      for (i=0; i<list.length; i++) {
          if (endsWith(list[i], "/"))
              processFiles(""+dir+list[i]);
          else {
             showProgress(n++, count);
             path = dir+list[i];
             processFile(path);
          }
      }
  }

  function processFile(path) {
       if (endsWith(path, ".tif")) {
           open(path);
           run("Subtract Background...", "rolling=50 white");
           save(path);
           close();
      }
  }

But I don’t understand how to transform my macro into a function in order to edit the processFile() function as it is mentionned.

I also don’t know if I should edit only the very last one function processFile(path) or the last two function processFile(dir) and function processFile(path)


So basically my question is, how can I merge those two macros???

Thank you very much.
I love collaborating

1 Like

You are correct that you want to put the logic into the processFile(path) function. Something like this:

// "BatchProcessFolders"
//
// This macro batch processes all the files in a folder and any
// subfolders in that folder. In this example, it runs the Subtract 
// Background command of TIFF files. For other kinds of processing,
// edit the processFile() function at the end of this macro.

   requires("1.33s"); 
   dir = getDirectory("Choose a Directory ");
   setBatchMode(true);
   count = 0;
   countFiles(dir);
   n = 0;
   processFiles(dir);
   //print(count+" files processed");
   
   function countFiles(dir) {
      list = getFileList(dir);
      for (i=0; i<list.length; i++) {
          if (endsWith(list[i], "/"))
              countFiles(""+dir+list[i]);
          else
              count++;
      }
  }

   function processFiles(dir) {
      list = getFileList(dir);
      for (i=0; i<list.length; i++) {
          if (endsWith(list[i], "/"))
              processFiles(""+dir+list[i]);
          else {
             showProgress(n++, count);
             path = dir+list[i];
             processFile(path);
          }
      }
  }

  function processFile(path) {
       if (endsWith(path, ".tif")) {
           open(path);
           dir=getDirectory("image"); 
           name = File.getName(dir); 
           saveAs("tiff", File.directory+name);
           close();
      }
  }

I did not test, but that is how you would combine those two pieces of code.

2 Likes

Hey thanks a lot.

I think it is very close, but it doesn"t do anything…

Still working on it.

Thanks people

I suggest adding print statements. Something like this:

print("processFile: path=" + path + ", dir=" + dir + ", name=" + name);

And put it immediately before the saveAs call. Then you’ll get more information about what is going on.

Also, have you perused the Scripting with Fiji slides? They walk you through a lot of stuff about how to write macros. There is also a video recording now!

No I didn’t, and I most likely won’t…

Anyway, this thing is both challenging and time consuming but I achieved the 1st step: making a copy of each file with a new name based on each file’s own directory. Although my trick for the name works, it saves in the main directory that I select first but not in each subfolder - meaning, not in each image’s own directory — is that clear…?

I am stil happy with what I’ve done! I just did a simple modification of the built-in “BatchProcessFolders” macro.

For those of you who might be interested, enjoy!

// "BatchProcessFolders"
//
// This macro batch processes all the files in a folder and any
// subfolders in that folder. In this example, it runs the Subtract 
// Background command of TIFF files. For other kinds of processing,
// edit the processFile() function at the end of this macro.

   requires("1.33s"); 
   dir = getDirectory("Choose a Directory "); // my trick
   name = File.getName(dir); // my trick

   setBatchMode(true);
   count = 0;
   countFiles(dir);
   n = 0;
   processFiles(dir);
   //print(count+" files processed");
   
   function countFiles(dir) {
      list = getFileList(dir);
      for (i=0; i<list.length; i++) {
          if (endsWith(list[i], "/"))
              countFiles(""+dir+list[i]);
          else
              count++;
      }
  }

   function processFiles(dir) {
      list = getFileList(dir);
      for (i=0; i<list.length; i++) {
          if (endsWith(list[i], "/"))
              processFiles(""+dir+list[i]);
          else {
             showProgress(n++, count);
             path = dir+list[i];
             processFile(path);
          }
      }
  }

  function processFile(path) {
       if (endsWith(path, "C001.tif")) { // my trick, specific to my filename
           open(path); 
           saveAs("tiff", File.getParent(path)+name); // my trick for the name but it saves in the parent folder of all subdirectories
           close();
      }
  }
1 Like