Work with getFileList


#1

Dear Helpers,

I’m using a demo code to list all files of an directory.

https://imagej.nih.gov/ij/macros/ListFilesRecursively.txt

All files are formated like this ‘’‘vesti export_25.tif_26Veneer_Komposit.txt’’’

I need to get the file number, in this case 26.
How can I achieve this?

The reason for this is, that all existing files are all ready examined.
And want to show the next examiner wich files are to process.
All text files are related to a image in an image sequence from 1 to 35.

The next step would be: if the slice number is (in this case) 26 then show message (or a mark in the picture).
So the examiner can move to the next one. This step i guess i can achieve on my own.
But working with the file list contents is a bit tricky for me. Maybe I can use some string operations. But I dont know how to do this. Maybe somone is willing to help me.

I hope you are able to understand my problem.

Thank you

Tobias


#2

Good day Tobias,

the following ImageJ-macro should do what you want.

fileName = “vesti export_25.tif_26Veneer_Komposit.txt”;
subStringArray = split( fileName, “_” );
number = parseInt( substring( subStringArray[2], 0, 2 ) );
print( number );

HTH

Herbie


#3

Thank you Herbie,

that is looking good . But now I need to find a workaround, if file name don’t contains two digits.

For example there is : vesti export_25.tif_26Veneer_Komposit.txt
and: vesti export_2.tif_3Veneer_Komposit.txt

Right now it prints NaN if the filename is like the second one.

Is there a way to include both versions?

My code looks like this:

dir = getDirectory("Choose a Directory ");
count = 1;
print("\\Clear");
listFiles(dir);

function listFiles(dir) {
 setBatchMode(true);
 list = getFileList(dir);
 for (i=0; i<list.length; i++) {
    if (endsWith(list[i], "/"))
       listFiles(""+dir+list[i]);
    else
       //print((count++) + ": " + dir + list[i]); 				//prints file List
 action(dir, list[i]);
 setBatchMode(false);
 }
}

function action(dir, fileName) {
fileName = list[i];
subStringArray = split( fileName, "_" );
number = parseInt( substring( subStringArray[2], 0, 2 ) );
print( number );
}

With this code I get a list of all .txt files in a specific directory. Or more accuratly I only get the number. Sometimes there are over 100 files in that list.
But I dont need them to be in an list. I need them to be in a kind of array wich I can acces to check if any of the numbers match the current slice number of an image sequence.

Can you help me with that as well?

Best

Tobias


#4

Tobias,

a macro solution for your initial question could look like this:

//fileName = “vesti export_25.tif_26Veneer_Komposit.txt”;
fileName = “vesti export_25.tif_3Veneer_Komposit.txt”;
subStringArray = split( fileName, “_” );
if ( lengthOf( subStringArray[2] ) == 7 ) { digits = 1; } else { digits = 2; }
number = parseInt( substring( subStringArray[2], 0, digits ) );
print( number );

If necessary, you could easily adapt this code for numbers with more than 2 digits.

However, what you write about your code isn’t clear to me.

Regards


#5

Thank you again Herbie, this was the solution :slight_smile:

Well, it is hard to explain for me.
For example, with both files from above, we now have a short list, containing two numbers.

26 and 3

Right now they are printet in the log window.
What I want, is to check automatically if any of these numbers matches the current slice number of an image sequence.
But I guess I have to put the numbers in a resultstable or an array. I don’t really know what possibiltiys there are to achieve this.

Best regards

Tobias


#6

Tobias,

evidently it is difficult to help if it is hard for you to explain what you want …

“[…] if any of these numbers matches the current slice number of an image sequence.”

I assume that an image sequence is open in ImageJ and that a certain slice is visible at the moment. Then

sliceNo = getSliceNumber();

gives you the currently visible slice number.

Consequently, you write a loop in which you compare the current slice number with the numbers you’ve got from the text file names. Writing loops is described here:
https://imagej.nih.gov/ij/developer/macro/macros.html
The available “Built-in Macro Functions” of ImageJ are documented here:
https://imagej.nih.gov/ij/developer/macro/functions.html#getSliceNumber

So go ahead and good luck

Herbie


#7

2 options to write your numbers in an array:

list = getFileList(dir);

//create array with length of your file list
numberArray = newArray(list.length);
//loop that extracts the number, code from Herbie
for (i=0; i<list.length; i++){
print("i= " +i);
fileName = list[i];
subStringArray = split( fileName, “_” );
if ( lengthOf( subStringArray[2] ) == 7 ) { digits = 1; } else { digits = 2; }
number = parseInt( substring( subStringArray[2], 0, digits ) );
print( number );
numberArray[i] = number;
}

//start with empty array
numberArray = newArray();
//loop that extracts the number, code from Herbie
for (i=0; i<list.length; i++){
print("i= " +i);
fileName = list[i];
subStringArray = split( fileName, “_” );
if ( lengthOf( subStringArray[2] ) == 7 ) { digits = 1; } else { digits = 2; }
number = parseInt( substring( subStringArray[2], 0, digits ) );
print( number );
numberArray = Array.concat(numberArray, number);
}

*question to the forum pros: How can I indent a line to make it more readable?

As Herbie pointed out there might be more elegant ways to achieve what you want.
What I get is that you want to process only parts of files in a directory (A) which have not yet been processed? Another approach could be to save the processed ones in a new directory (B) and then only process files which are not yet element of B.
A useful command: matches(string, regex)/!matches(string, regex). Works also with elements of arrays.


#8

I’m sorry Herbie,

I’m still quite new to scripting and english is not my mother tongue.

Thats what I want to do, but I dont know how to compare them.
There is an Image Sequence open and I want to compare the slices with the numbers in the list. If any of these aquiered numbers matches the slice number, there should be a message for the examiner that he/she can skip this slice and examine the next one.

This is the loop I came up with. But it always displays the massage, because the variable “number” does not contain all the listed numbers.
How can I compare the numbers in my list with the slice numbers?

function messages(number) {
    while (getSliceNumber() !=number) {
	showStatus("Measure");
	else
	}
}

I couldn’t find some examples using the matches commands you pointed out. But it sounds prommising.

I hope you guy’s dont give up on me :slight_smile:

Best regards

Tobias


#9

Tobias,

if you need a functionality that requires a macro and you’ve received help from the forum, you should really think about investing some time to learn writing macros based on the help you’ve received.

Here is an example that does what you want:

requires( "1.51p" )
// For preparation only
run( "MRI Stack (528K)" );
setSlice( 13 );
stack = getImageID();
txtPath = getDirectory( "home" ) + "TextFiles/";
File.makeDirectory( txtPath );
for ( i=1; i<15; i++ ) {
  	fileName = "vesti export_" + i-1 + ".tif_" + i + "Veneer_Komposit.txt";
	File.saveString( "Just some text", txtPath + fileName );
}
// End of preparation
showMessage( "Here comes the beef." );
selectImage( stack );
sliceNumber = getSliceNumber();
txtDir = getDirectory( "Choose a Directory" );
fileNameArray = getFileList( txtDir );
for ( i=0; i< fileNameArray.length; i++ ) {
	subStringArray = split( fileNameArray[i], "_" );
	if ( lengthOf( subStringArray[2] ) == 7 ) { digits = 1; } else { digits = 2; }
	number = parseInt( substring( subStringArray[2], 0, digits ) );
	if  ( sliceNumber == number ) showMessage( "Skip Slice " + sliceNumber  + " !" );
}

EDIT:
In case it is not clear, this is a stand-alone macro.
When the file dialog comes up, you are to select the directory named “TextFiles”, located in the home directory.
If the argument of setSlice is <=14, then the “Skip Slice”-message is presented, if it is >14 the message is not shown.

Have fun

Herbie


#10

Thank you for your time and effort herby,

I know i have to learn but sometimes I just don’t know whats possible. And it would take more time than I can effort.
I’ll look into your script and try to understand what you did in it.

and again, thank you very much

Tobias


#11

Tobias,
Do you know this very useful list of macro functions? (EDIT: which Herbie already linked above)
https://imagej.nih.gov/ij/developer/macro/functions.html
Together with the Macro recorder [Plugins > Macros > Record], some trial-and-error (start with minimal examples before you apply it to your code) and a minimal understanding of loops and functions you can get quite far.

@Herbie: Although this is not required to solve Tobias problem, do you know some elegant way to test if a string/number is element of an array? I had the problem myself and could not come up with a better solution than iterating through the whole array which results in ugly code ( if (matches(string, array[i]) { do whatever } ). More complex boolean operators such as %in% do not seem to work in ImageJ macro language.


#12

Good day Jenny,

first of all I’ve pointed Tobias already to the relevant websites (see my earlier message).

“test if a string/number is element of an array”

In any case you need to loop through the array. However, there are scripting languages that do the loop behind the scenes, i.e. you don’t have to write it explicitely.

I don’t understand why you think that ugly code is required.
I don’t think that the solution in Tobias’ case consists of ugly code.

Regards

Herbie


#13

Hello Herbie,

To clarify, my question was referring to a related problem I observed myself, not Tobias problem/solution. I was just wondering if there is a better function for this purpose than writing such loop (which works fine but maybe there are better/nicer solutions).

Thinking back to my first trial-and-error (a lot of error!) steps with the ImageJ macro language I think a newbie can use any encouragment he/she can get.


#14

Jenny,

concerning encouragement:
Please be so kind and follow the thread to see what help Tobias has already received.
It is not the task of a forum to do the work for others but to help them to be able to help themselves.

Regards

Herbie


#15

I agree with you Herbie. However, if you are a biologist with urge to have the data and without previous scripting experience, it takes some time and stamina to get your first macros running. Please do not attack me for encouraging Tobias that he will get there and that it is well worth to invest the time. I am sure your example script will help.

Kind regards


#16

Thank you both for your help,

I found now a suitable solution for my task.

Because I wasn’t able to compare the current slice number of my Image Stack with the file list, I decided to try another approach.
Since I now can print the numbers into a list, I can use this to set the slice to the current extracted number. Only those slices wich are in the list, are getting now a marking with the makeOval command.

This is the code I managed to write with your help @Herbie

dir = getDirectory("Choose a Directory");
 	print("\\Clear");
 	listFiles(dir);

function listFiles(dir) {
 setBatchMode(true);
 list = getFileList(dir);
 for (i=0; i<list.length; i++) {
    if (endsWith(list[i], "/"))
       listFiles(""+dir+list[i]);
    else
    	action(dir, list[i]);
 		setBatchMode(false);	
 }
}

function action(dir, fileName) {
     fileName = list[i];
     subStringArray = split( fileName, "_" );
     if ( lengthOf( subStringArray[2] ) == 9 ) { digits = 1; } 
      else { digits = 2; }
      number = parseInt( substring( subStringArray[2], 0, digits ) );
       //print( number );
       setSlice( number );
       addMarking();
}

function addMarking () {
    makeOval(20, 20, 20, 20);
    run("Draw", "slice");
    run("Select None");
} 

Thank you both for your help @Herbie and @jostrop

Even though I was not using your second example.

Best regards

Tobias


#17

Interesting Tobias,

that my code doesn’t work for you because it does what you’ve described when I run it here. But happy to hear that you found a solution.

Best

Herbie


#18

Well the code is working fine. But it is just showing a message for one specific slice, in this case 13 right?. But I have multiple file wich needs to be skipped.
But I guess I was just not able to understand whats needs to be changed to suit my needs.

Cheers


#19

Tobias,

not sure what this

But I have multiple file wich needs to be skipped.

means.

As far as I’ve understood, you’ve wanted the following:

if ( sliceNumber == number ) showMessage( “Skip Slice " + sliceNumber + " !” );

That is, whenever the currently visible slice number equals the number in at least one of the text file names, the skip-message should be shown.

Therefore, the macro loops through all text files in the “TextFiles”-folder to be found in your home directory.

Somehow puzzled

Herbie


#20

Herbie,

maybe this is it. The getDirectory window is opening and I choose the folder where my (originally) text files are, but the second I hit enter, it tells me "Skip Slice 13!"
Has it anything to do that I’m working on a Mac right now? Because there is no “home directory”?

Well lets say I have a image sequence (stack) of 35 images. All images should have a one text file with measurements in it. But some haven’t, because the first examiner just din’t processed them. I need to find out wich are examined and wich not. Sometimes it is just one sometimes there are 20 slices which where not examined. For example slice 1 to 5 where examined but 6 to 15 not, but 17 to 35 where. I want to mark the slices which where not examined in the first place.

Thank you herby that you are still interested in this :slight_smile:

Best tobias