Image J, Slide J plugin-Unable to save all mosaic tiles?! Help!

I am using a plugin on ImageJ (FIJI) called Slide J to break my NDP (nanozoomer) files into mosaic tiles for particle analysis. I can’t for the life of me however figure out how to save every mosaic image as a TIFF, or preferably a JPEG.

I have put the .jar file directly in the plugins folder, but I can’t seem to find where in the .jar or .java file to write a command to automatically save every mosaic tile.

Could someone please assist me? The .java file for the plugin is as follows. All files available on Github via the following link: https://github.com/MITEL-UNIUD/SlideJ

import ij.plugin.;
import ij.
;
import ij.process.;
import ij.gui.
;
import ij.util.Tools;
import ij.io.*;
import ij.macro.Interpreter;
import ij.IJ;
import ij.plugin.PlugIn;

import java.util.;
import java.util.GregorianCalendar;
import java.awt.image.ColorConvertOp;
import java.awt.
;
import java.awt.event.;
import java.io.
;
import java.util.Vector;
import java.io.File;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.text.SimpleDateFormat;

import loci.formats.gui.BufferedImageReader;
import loci.formats.FormatException;
import loci.common.services.ServiceFactory;
import loci.formats.ImageReader;
import loci.formats.ImageWriter;
import loci.formats.meta.IMetadata;
import loci.formats.services.OMEXMLService;
import loci.plugins.LociImporter;
import fiji.util.gui.GenericDialogPlus;

/**
MITEL
Dept. of Mathematics, Computer Science and Physics University of Udine, Italy
*/

/**
SlideJ is an ImageJ plugin for automated processing of Whole Slide Images.
SlideJ has been tested on slides in the following formats:
Aperio .SVS, Leica .SCN, Hamamatsu .NDPI, Mirax, Generic tiled TIFF and regular TIFF.
The user is allowed to process multiple images present in a folder and store the eventual results in a
different folder by setting up paths in the “input” and “output” fields,respectively.
Since digital slide processing could be a time consuming task, SlideJ allows the user to launch very
long series of unsupervised tasks which can be performed in free time.
SlideJ is released uner LGPL v3 License.
*/

public class SlideJ_ implements PlugIn{
private GenericDialogPlus gd;
private String macro;
private String cancel_file;
private int serie;
private int crop;
private int overlap;

private static final String code = {
“[Select from list]”,
“Yes”,
“No”,
};

public void run(String arg) {

/* The interface of the plugin is a modal dialog that resembles the one implemented in ImageJ
   for batch macro execution. */
gd = new GenericDialogPlus("SlideJ");
gd.addDirectoryField( "input", "");
gd.addDirectoryField( "output", "");
gd.addDirectoryOrFileField( "macro", "");
gd.addStringField("Series: ", "1", 5);
gd.addStringField("Tile size: ", "1024", 10);
gd.setInsets(0, 0, 10);
gd.addStringField("Overlap: ", "0", 10);
gd.setInsets(0, 0, 10);
gd.addChoice("Cancel temporary tiles?", code, code[1]);

gd.showDialog();

String inputPath = gd.getNextString();
String outputPath = gd.getNextString();
String macro = gd.getNextString();
String serie_str = gd.getNextString();
String crop_str = gd.getNextString();
String overlap_str = gd.getNextString();

serie = Integer.parseInt(serie_str);
crop = Integer.parseInt(crop_str);
overlap = Integer.parseInt(overlap_str);
cancel_file =  gd.getNextChoice();

if (gd.wasCanceled()) {
    return;
}

if (inputPath.equals("")) {
    error("Please choose an input folder");
    return;
}
inputPath = addSeparator(inputPath);
File f1 = new File(inputPath);
if (!f1.exists() || !f1.isDirectory()) {
    error("Input does not exist or is not a folder\n \n"+inputPath);
    return;
}
if (outputPath.equals("")) {
    error("Please choose an output folder");
    return;
}
outputPath = addSeparator(outputPath);
File f2 = new File(outputPath);
if (!f2.exists() || !f2.isDirectory()) {
    error("Output does not exist or is not a folder\n \n"+outputPath);
    return;
}
if (macro.equals("")) {
    error("Please choose a macro file");
    return;
}
File f3 = new File(macro);
if (!f3.exists()) {
    error("Macro does not exist \n"+macro);
    return;
}

ImageJ ij = IJ.getInstance();
	if (ij!=null)
        ij.getProgressBar().setBatchMode(true);
IJ.resetEscape();

File[] list1=f1.listFiles();
int MAX=list1.length;
long startTime = 0;
try{
    FileWriter w;
    w=new FileWriter(outputPath + "SlideJlog.txt", true);
    GregorianCalendar now = new GregorianCalendar();
    SimpleDateFormat dateformat = new SimpleDateFormat("dd/MM/yyyy - HH:mm:ss");
    w.write("Start SlideJ Plugin: " +dateformat.format( now.getTime() ) + "\n\r");
    w.flush();
    for (int i = 0; i<MAX; i++){
        
    startTime = System.currentTimeMillis();//Time recorder
    
        
    ImageReader imageReader = new ImageReader(); //Byte reader
    BufferedImageReader buffImageReader = new BufferedImageReader();
    String inputName =list1[i].getName();
    if(! inputName.endsWith(".DS_Store")){
        
        String imgPath = inputPath + inputName;
        System.out.println(imgPath);
        try
        {
            imageReader.setId(imgPath);
            BufferedImageReader buffImageReaderTest = new BufferedImageReader();
            buffImageReaderTest.setId(imgPath);
            int s = (serie - 1);
            buffImageReaderTest.setSeries(s);
            int buffYTest = buffImageReaderTest.getSizeY();
            int buffXTest = buffImageReaderTest.getSizeX();
            int t = (int) crop;
            int over = (int) overlap;
            int tilex = t;
            int x_coor = 0;
            for( int j = 0; j == 0; x_coor = x_coor + t - over) {
                int tiley = t;
                int y_coor = 0;
                
                for( int z = 0;z == 0; y_coor = y_coor + t - over) {
                    
                   if((x_coor + t) >= buffXTest)
                   {
                       tilex = buffXTest - x_coor;
                       j = 1;
                   }
                    
                    if((y_coor + t) >= buffYTest)
                    {
                        tiley = buffYTest - y_coor ;
                        z = 1;
                        
                    }
                    
                    
                    BufferedImage rgbImage = buffImageReaderTest.openImage(0,x_coor, y_coor, tilex, tiley);
                    /* Tiles are stored in TIFF format with a file name that reflects their position 
                       on the overall digital slide according to the following template:
                       <OriginalFileName.ext>__<series>_<Xorigin>_<Yorigin>.tif */
                    File fileTileOut = new File(outputPath +inputName+"__"+serie+"_"+x_coor+"_"+ y_coor+".tif");
                    String title = inputName+"__"+serie+"_"+x_coor+"_"+ y_coor+".tif";
                    ImagePlus imp = new ImagePlus(title,rgbImage);
                    IJ.run(imp, "RGB Color", "");
                    String path_imprgb = outputPath +inputName+"__"+serie+"_"+x_coor+"_"+ y_coor+".tif";
                    //imp.close();
                    IJ.saveAs(imp, "Tiff", path_imprgb );
                    //imp.close();
                    imp.flush();
                    IJ.open(path_imprgb);
                    ImagePlus imp1 = IJ.getImage();
                    IJ.runMacroFile(macro);//Macro application
                    if(cancel_file.equals("Yes")){
                          //imp1.close();
                          imp1.flush();
                          fileTileOut.delete();
                        
                    }
                     else if(cancel_file.equals("No")){
                    
                    //imp1.close();
                    imp1.flush();
                    }
                 
                
                    
                }
            }
            long endTime   = System.currentTimeMillis();
            long totalTime = endTime - startTime;
            
            
            w.write("File " +inputName+ ", series number " +serie+ ", tile size " +crop+ ", overlap " +overlap+ ", time " +totalTime+ " ms. "+ "\n\r");
            w.flush();
        }
        catch (FormatException exc)
        {
            System.out.println("Format exception" + exc.getMessage());
        }
        catch (IOException exc)
        {
            System.out.println("I/O exception" + exc.getMessage());
        }
        
        
        
    }
        
}

}
catch (IOException e)
{
e.printStackTrace();
}

}

String addSeparator(String path) {
	if (path.equals("")) return path;
	if (!(path.endsWith("/")||path.endsWith("\\")))
		path = path + File.separator;
	return path;
}

void error(String msg) {
	IJ.error("Error:", msg);
}

public void run() {
    
}

}

I don’t know about SlideJ, but the documentation for doing this with QuPath is here.

Ah! You are amazing!

I haven’t used QuPath before, is the code inserted into a plugin feature similar to ImageJ? Or could you please provide me with a few pointers as to how best to execute the tile exporter? Thanks!

2 Likes

Use Automate → Show script editor, paste the script there and choose Run → Run from the menus.

But you might not need to export all the tiles, and there are other ways to export image regions in an ImageJ-friendly way with no scripting required. See https://qupath.readthedocs.io/en/latest/docs/advanced/imagej.html

Lots of documentation on other things through readthedocs, videos at https://www.youtube.com/c/qupath and the forum tag here #qupath - and the webinar in a few weeks at NEUBIAS Academy :slight_smile:

1 Like

Oh fabulous, I have registered to attend the Webinar!

I apologise in advance as it will take me a while to work through all the documentation (I am new to image analysis), but when running the TileExporter script, it is returning an error at line 18. I am unsure specifically which values I need to adjust in order to run the script on my computer.

If you could please help with this I’ll try not to ask anymore questions until i have had a thorough look through the docs! :slight_smile:

Screen Shot 2020-04-09 at 19.23.51|690x318

No problem! I suspect the issue is that the script expects you to be working in a project, which it uses to figure out the output directory. It isn’t strictly necessary, but it generally helps to use projects in QuPath. If you don’t want to, you can replace the line

def pathOutput = buildFilePath(PROJECT_BASE_DIR, 'tiles', name)

with something like

def pathOutput = "C:/where/your/files/should/go"

If that isn’t the explanation for the error, can you paste the exact error message?

I have set the output path to a directory on my desktop that contains the image I want to tile, but it is now returning the following error:

Screen Shot 2020-04-09 at 19.41.35 I’ll

Do I need to change the value for the down sample? Here is what the script says:

Ah, you’ll need to follow the links for the latest milestone release, not the latest stable release (hopefully they will be the same thing soon…): https://github.com/qupath/qupath/releases/latest

3 Likes

Also, the “inverted commas” are necessary when you specify a path in any script, so you’ll need to add them around "/Users/..."

1 Like

Amazing! I updated QuPath and created a project file and it worked!

One other question, is it possible to set the Width and Height of the exported tile, and also incorporate the x magnification in the name of the exported tile?

1 Like

Yes it is possible to set the width and height, just give two separate parameters instead of one:

.tileSize(512, 512)

instead of

.tileSize(512)

Also, if you want to include the downsampling factor/pixel size (I think that’s what you mean?) you can simply add it to the output folder name:

def pathOutput = "/Users/annabellesorby-adams/Desktop/IHC Trial_downsample_" + downsample

or

def pathOutput = "/Users/annabellesorby-adams/Desktop/IHC Trial_pixel_size_" + pixelSize

You will have to put that line after defining downsample/pixelSize though (not before, like it currently is in the script screenshot that you posted).

2 Likes

In case it might simplify your workflow, depending on your particles, you might be able to use the built in QuPath cell detection to find particles in your whole image all at once (if they are somewhat roundish), without splitting it up. And then you can run that for multiple whole slide images. Though, as Pete pointed out, running the macro through ImageJ and returning the results to the whole slide image might be useful for more complicated structures.

Hi Pete,

Thanks so much for your help again! I have had a look at all your YouTube videos and they are super helpful.

I do however have a few questions about exporting tiles from a ROI. I understand that you can select a ROI and choos Analyze-Region Identification-tiles and super pixels-create tiles, but is there a way to automatically export each of these tiles? Any help/information would be amazing! Thanks.

Hi @asorbyadam, is this the same question? Export tiles from ROI in QuPath