0

I have been attempting to program a solution for ImageJ to process my images.

I understand how to get a directory, run commands on it, etc etc. However I've run into a situation where I now need to start using some type of search function in order to pair two images together in a directory full of image pairs.

I'm hoping that you guys can confirm I am on the right direction and that my idea is right. So far it is proving difficult for me to understand as I have less than even a month's worth of experience with Java. Being that this project is directly for my research I really do have plenty of drive to get it done I just need some direction in what functions are useful to me.

I initially thought of using regex but I saw that when you start processing a lot of images (especially with imagej which it seems does not dump data usage well, if that's the correct way to say it) that regex is very slow.

The general format of these images is:

  • someString_DAPI_0001.tif
  • someString_GFP_0001.tif
  • someString_DAPI_0002.tif
  • someString_GFP_0002.tif
  • someString_DAPI_0003.tif
  • someString_GFP_0003.tif

They are in alphabetical order so it should be able to go to the next image in the list. I'm just a bit lost on what functions I should use to accomplish this but I think my overall while structure is correct. Thanks to some help from Java forums. However I'm still stuck on where to go to next.

So far here is my code: Thanks to this SO answer for partial code

int count = 0;
getFile("C:\");

string DAPI;
string GFP;


private void getFile(String dirPath) {
    File f = new File(dirPath);
    File[] files = f.listFiles();

    while (files.length > 0) {
        if (/* File name contains "DAPI"*/){
            DAPI = File f;
            string substitute to get 'GFP' filename
            store GFP file name into variable
            do something(DAPI, GFP);
        }
        advance to next filename in list
    }
}

As of right now I don't really know how to search for a string within a string. I've seen regex capture groups, and other solutions but I do not know the "best" one for processing hundreds of images.

I also have no clue what function would be used to substitute substrings.

I'd much appreciate it if you guys could point me towards the functions best for this case. I like to figure out how to make it on my own I just need help getting to the right information. Also want to make sure I am not making major logic mistakes here.

Community
  • 1
  • 1
FrankyG
  • 182
  • 7
  • Look for the [String](http://docs.oracle.com/javase/7/docs/api/java/lang/String.html) class in java. It should provide you most of the methods for string manipulation – vsnyc Nov 12 '15 at 20:19
  • 1
    Are you sure that you want to use Java? Within ImageJ, you can use macros or any of the [scripting languages](http://fiji.sc/Scripting_toolbox#Opening.2C_processing.2C_and_saving_a_sequence_of_files_in_a_folder) (Groovy, Javascript, Python) that are quite well equipped to perform this kind of tasks. Together with a few `str.replace()` or `str.contains()` calls that are available in any of these languages, that should be sufficient, so you don't have to reinvent the wheel in Java. See also the [ImageJ forum](http://forum.imagej.net/). – Jan Eglinger Nov 12 '15 at 22:51

2 Answers2

1

It doesn't seem like you need regex if your file names follow the simple pattern that you mentioned. You can simply iterate over the files and filter based on whether the filename contains DAPI e.g. see below. This code may be oversimplification of your requirements but I couldn't tell that based on the details you've provided.

import java.io.*;


public class Temp {

  int count = 0;

  private void getFile(String dirPath) {
    File f = new File(dirPath);
    File[] files = f.listFiles();

    if (files != null) {
      for (File file : files) {
        if (file.getName().contains("DAPI")) {
          String dapiFile = file.getName();
          String gfpFile = dapiFile.replace("DAPI", "GFP");
          doSomething(dapiFile, gfpFile);
        }
      }
    }
  }

  //Do Something does nothing right now, expand on it.
  private void doSomething(String dapiFile, String gfpFile) {
    System.out.println(new File(dapiFile).getAbsolutePath());
    System.out.println(new File(gfpFile).getAbsolutePath());
  }

  public static void main(String[] args) {
    Temp app = new Temp();
    app.getFile("C:\\tmp\\");
  }

}

NOTE: As per Vogel612's answer, if you have Java 8 and like a functional solution you can have:

private void getFile(String dirPath) {
  try {
    Files.find(Paths.get(dirPath), 1, (path, basicFileAttributes) -> (path.toFile().getName().contains("DAPI"))).forEach(
      dapiPath -> {
        Path gfpPath = dapiPath.resolveSibling(dapiPath.getFileName().toString().replace("DAPI", "GFP"));
        doSomething(dapiPath, gfpPath);
      });
  } catch (IOException e) {
    e.printStackTrace();
  }
}

//Dummy method does nothing yet.
private void doSomething(Path dapiPath, Path gfpPath) {
  System.out.println(dapiPath.toAbsolutePath().toString());
  System.out.println(gfpPath.toAbsolutePath().toString());
}
vsnyc
  • 2,117
  • 22
  • 35
  • Is it generally good practice to use a null check for if statements? It's not something I did regularly but I'm guessing it helps avoid hangups? Thank you so much for the answer! Yes that's pretty much all I needed. I have more complicated plans for the program but until I run into something that I have spent a week trying to figure out I'm going to see if I can finish on my own. – FrankyG Nov 12 '15 at 20:28
  • String manipulation is one of the less good ideas (aside from using File) instead using Path provides a cleaner development experience and better compatibility – Vogel612 Nov 12 '15 at 20:29
  • Null check isn't always necessary, it depends on the method calls. In this case, f.listFiles() can return null hence the check. – vsnyc Nov 12 '15 at 20:40
  • @Vogel612, I updated the answer, but I don't see anything inherently wrong in the original approach. After all, File.listFiles() returning null isn't my idea. Cheers! – vsnyc Nov 12 '15 at 21:12
  • Thank you! Also sorry for the really basic questions. I do feel like I almost made you guys "give" the code to me, but really thanks for all the help. – FrankyG Nov 12 '15 at 22:23
  • Glad to have helped. No worries about the basic questions, we alI do that. See some of my Scala questions ;-) – vsnyc Nov 13 '15 at 00:47
  • @vsnyc Hey I'm still having trouble with this, I used this code: http://tinypic.com/r/fn63c2/9. I got these errors with it: http://tinypic.com/r/14vmoep/9. – FrankyG Nov 17 '15 at 16:36
  • There is a typo in your code, you have put parenthesis around dapiPath, look my code snippet for correct way to put it – vsnyc Nov 17 '15 at 16:52
1

Using java.io.File is the wrong way to approach this problem. What you're looking for is a Stream-based solution using Files.find that would look something like this:

 Files.find(dirPath, 1, (path, attributes) -> {
     return path.getFileName().toString().contains("DAPI");
 }).forEach(path -> {
    Path gfpFile = path.resolveSibling(/*build GFP name*/);
    doSomething(path, gfpFile);
 });

What this does is:

  • Iterate over all Paths below dirPath 1 level deep (may be adjusted)
  • Check that the File's name contains "DAPI"
  • Use these files to find the relevant "GFP"-File
  • give them to doSomething

This is preferrable to the files solution because of multiple things:

  1. It's significantly more informative when failing
  2. It's cleaner and more terse than your File-Based solution and doesn't have to check for null
  3. It's forward compatible, and thus preferrable over a File-Based solution

Files.find is available from Java 8 onwards

Vogel612
  • 5,620
  • 5
  • 48
  • 73
  • For resolveSibling(), will it basically find the GFP file by taking the "DAPI" string and replacing it with "GFP" and locating it that way? I'm a bit worried that when you say "build GFP name" that it would require the entire string to be built instead of just replacing the substring "DAPI". Hopefully I am explaining my thinking correctly. – FrankyG Nov 12 '15 at 20:55
  • @FrankyG The "Build GFP name" is basically `path.getFileName().toString().replace("DAPI", "GFP");` which works by only modifying the **file name** instead of working on the whole path – Vogel612 Nov 12 '15 at 21:40
  • Ah okay thank you. Sorry for the very basic questions, I'm really trying to give you guys room so you don't have to literally answer and "give" the code out to me. – FrankyG Nov 12 '15 at 22:22