package gdsc.smlm.ij.utils; /*----------------------------------------------------------------------------- * GDSC SMLM Software * * Copyright (C) 2013 Alex Herbert * Genome Damage and Stability Centre * University of Sussex, UK * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. *---------------------------------------------------------------------------*/ import java.awt.Label; import java.awt.TextField; import java.awt.event.ItemEvent; import java.awt.event.TextEvent; import java.io.File; import java.util.Arrays; import gdsc.core.ij.Utils; import ij.IJ; import ij.ImagePlus; import ij.gui.GenericDialog; import ij.io.Opener; import ij.plugin.FolderOpener; /** * Opens a series of images in a folder. The series is sorted numerically. * <p> * Adapted from {@link ij.plugin.FolderOpener } */ public class SeriesOpener { private String path; private String[] imageList = new String[0]; private int currentImage = 0; private int width = -1, height = -1; private boolean variableSize = false; private int numberOfThreads = 0; /** * Create an opener with the given path * * @param path */ public SeriesOpener(String path) { this.path = path; buildImageList(); } /** * Create an opener with the given path * * @param path * @param showDialog * Open a dialog and allow the user to filter the images * @param numberOfThreads * Set the number of threads specified in the input dialog. If zero then this field is not shown. */ public SeriesOpener(String path, boolean showDialog, int numberOfThreads) { this.path = path; this.numberOfThreads = Math.abs(numberOfThreads); buildImageList(); if (showDialog) filterImageList(); } private void buildImageList() { String directory = path; if (directory == null) return; // Get a list of files File[] fileList = (new File(directory)).listFiles(); if (fileList == null) return; // Exclude directories String[] list = new String[fileList.length]; int c = 0; for (int i = 0; i < list.length; i++) if (fileList[i].isFile()) list[c++] = fileList[i].getName(); list = Arrays.copyOf(list, c); // Now exclude non-image files as per the ImageJ FolderOpener FolderOpener fo = new FolderOpener(); list = fo.trimFileList(list); if (list == null) return; imageList = fo.sortFileList(list); } /** * Returns the number of images in the series. Note that the number is based on a list of filenames; each image is * only opened with the nextImage() function. * * @return The number of images in the series */ public int getNumberOfImages() { return imageList.length; } /** * Returns the path to the directory containing the images * * @return the path */ public String getPath() { return path; } /** * Returns the names of the images in the series * * @return The names of the image files */ public String[] getImageList() { return imageList; } /** * Get the next image in the series (or null if no more images) * <p> * Only images that match the width and height of the first image are returned. * * @return The next image in the series */ public ImagePlus nextImage() { ImagePlus imp = null; while (currentImage < imageList.length && imp == null) { imp = openImage(imageList[currentImage++]); } return imp; } private ImagePlus openImage(String filename) { //System.out.printf("Opening %s %s\n", path, filename); Opener opener = new Opener(); opener.setSilentMode(true); Utils.setShowProgress(false); ImagePlus imp = opener.openImage(path, filename); Utils.setShowProgress(true); if (imp != null) { // Initialise dimensions using first image if (width == -1) { width = imp.getWidth(); height = imp.getHeight(); } // Check dimensions if (!variableSize) { if (width != imp.getWidth() || height != imp.getHeight()) imp = null; } } return imp; } // Used to filter the image list private int n, start; private int increment; private String filter; private boolean isRegex; private void filterImageList() { String[] list = imageList; ImagePlus imp = nextImage(); // Reset image list currentImage = 0; imageList = new String[0]; if (imp != null && showDialog(imp, list)) { // Filter by name if (filter != null && (filter.equals("") || filter.equals("*"))) filter = null; if (filter != null) { int filteredImages = 0; for (int i = 0; i < list.length; i++) { if (isRegex && list[i].matches(filter)) filteredImages++; else if (list[i].indexOf(filter) >= 0) filteredImages++; else list[i] = null; } if (filteredImages == 0) { if (isRegex) IJ.error("Import Sequence", "None of the file names match the regular expression."); else IJ.error("Import Sequence", "None of the " + list.length + " files contain\n the string '" + filter + "' in their name."); return; } String[] list2 = new String[filteredImages]; int j = 0; for (int i = 0; i < list.length; i++) { if (list[i] != null) list2[j++] = list[i]; } list = list2; } // Process only the requested number of images if (n < 1) n = list.length; if (start < 1 || start > list.length) start = 1; imageList = new String[list.length]; int count = 0; for (int i = start - 1; i < list.length && count < n; i += increment, count++) { imageList[count] = list[i]; } imageList = Arrays.copyOf(imageList, count); } } private boolean showDialog(ImagePlus imp, String[] list) { int fileCount = list.length; FolderOpenerDialog gd = new FolderOpenerDialog("Sequence Options", imp, list); gd.addMessage("Folder: " + path + "\nFirst image: " + imp.getOriginalFileInfo().fileName + "\nWidth: " + imp.getWidth() + "\nHeight: " + imp.getHeight() + "\nFrames: " + imp.getStackSize()); gd.addNumericField("Number of images:", fileCount, 0); gd.addNumericField("Starting image:", 1, 0); gd.addNumericField("Increment:", 1, 0); gd.addStringField("File name contains:", "", 10); gd.addStringField("or enter pattern:", "", 10); if (numberOfThreads > 0) gd.addNumericField("Series_number_of_threads:", numberOfThreads, 0); gd.addMessage("[info...]"); gd.showDialog(); if (gd.wasCanceled()) return false; n = (int) gd.getNextNumber(); start = (int) gd.getNextNumber(); increment = (int) gd.getNextNumber(); if (increment < 1) increment = 1; filter = gd.getNextString(); String regex = gd.getNextString(); if (!regex.equals("")) { filter = regex; isRegex = true; } if (numberOfThreads > 0) numberOfThreads = Math.abs((int) gd.getNextNumber()); return true; } /** * Set to true to allow subsequent images after the first to have different XY dimensions * * @param variableSize * True for vairable size images */ public void setVariableSize(boolean variableSize) { this.variableSize = variableSize; } /** * @return The number of threads specified in the input dialog. */ public int getNumberOfThreads() { return numberOfThreads; } } class FolderOpenerDialog extends GenericDialog { private static final long serialVersionUID = -7650551696737633887L; ImagePlus imp; int fileCount; String[] list; public FolderOpenerDialog(String title, ImagePlus imp, String[] list) { super(title); this.imp = imp; this.list = list; this.fileCount = list.length; } protected void setup() { setStackInfo(); } public void itemStateChanged(ItemEvent e) { } public void textValueChanged(TextEvent e) { setStackInfo(); } void setStackInfo() { int n = getNumber(numberField.elementAt(0)); int start = getNumber(numberField.elementAt(1)); int inc = getNumber(numberField.elementAt(2)); // Filter by name TextField tf = (TextField) stringField.elementAt(0); String filter = tf.getText(); tf = (TextField) stringField.elementAt(1); String regex = tf.getText(); java.util.regex.Pattern p = null; if (!regex.equals("")) { filter = regex; p = java.util.regex.Pattern.compile(filter); } if (!filter.equals("") && !filter.equals("*")) { int n2 = 0; for (int i = 0; i < list.length; i++) { if (p != null && p.matcher(list[i]).matches()) n2++; else if (list[i].indexOf(filter) >= 0) n2++; } if (n2 < n) n = n2; } // Now count using the input settings if (start < 1 || start > n) start = 1; if (inc < 1) inc = 1; int count = 0; for (int i = start - 1; i < list.length && count < n; i += inc, count++) ; int frames = imp.getStackSize() * count; ((Label) theLabel).setText(String.format("%d image%s (%d frame%s)", count, (count == 1) ? "" : "s", frames, (frames == 1) ? "" : "s")); } public int getNumber(Object field) { TextField tf = (TextField) field; String theText = tf.getText(); Double d; try { d = new Double(theText); } catch (NumberFormatException e) { d = null; } if (d != null) return (int) d.doubleValue(); else return 0; } }