From e31afb77ed1505a6a8d0094a30d274970bf28300 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 10:29:35 +0100 Subject: [PATCH 01/33] Bump version and dependency versions --- pom.xml | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/pom.xml b/pom.xml index 63d14ce..aa6dfe8 100644 --- a/pom.xml +++ b/pom.xml @@ -6,12 +6,12 @@ pom-scijava org.scijava - 33.2.0 + 36.0.0 fr.igred omero_batch-plugin - 1.0.5 + 2.0.0-SNAPSHOT omero_batch-plugin ImageJ plugin to batch process images from OMERO. @@ -114,8 +114,6 @@ UTF-8 - 8 - 8 gpl_v2 MICA & GReD @@ -144,7 +142,7 @@ fr.igred simple-omero-client - 5.12.1 + 5.16.0 org.scijava @@ -174,9 +172,7 @@ - org.apache.maven.plugins maven-assembly-plugin - 2.6 package @@ -204,16 +200,4 @@ - - - - - maven-javadoc-plugin - - false - - - - - From cf27a6ae11aaaa09c031dd65aab5c800a153ffc4 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 10:35:07 +0100 Subject: [PATCH 02/33] Rename OMEROBatchRunner.java to LocalBatchImage.java --- .../ij/{macro/OMEROBatchRunner.java => io/LocalBatchImage.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/java/fr/igred/ij/{macro/OMEROBatchRunner.java => io/LocalBatchImage.java} (99%) diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/io/LocalBatchImage.java similarity index 99% rename from src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java rename to src/main/java/fr/igred/ij/io/LocalBatchImage.java index ebf2f77..bea1c2f 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/io/LocalBatchImage.java @@ -14,7 +14,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin * Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package fr.igred.ij.macro; +package fr.igred.ij.io; import fr.igred.ij.gui.ProgressDialog; import fr.igred.omero.Client; From 71de424441db83967b990315fb22b7b1694bd11f Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 10:52:42 +0100 Subject: [PATCH 03/33] Rename OMEROBatchRunner class to LocalBatchImage --- .../java/fr/igred/ij/io/LocalBatchImage.java | 74 ++----------------- .../java/fr/igred/ij/io/package-info.java | 1 + 2 files changed, 6 insertions(+), 69 deletions(-) diff --git a/src/main/java/fr/igred/ij/io/LocalBatchImage.java b/src/main/java/fr/igred/ij/io/LocalBatchImage.java index bea1c2f..7b4a72d 100644 --- a/src/main/java/fr/igred/ij/io/LocalBatchImage.java +++ b/src/main/java/fr/igred/ij/io/LocalBatchImage.java @@ -16,104 +16,40 @@ */ package fr.igred.ij.io; -import fr.igred.ij.gui.ProgressDialog; -import fr.igred.omero.Client; -import fr.igred.omero.annotations.TableWrapper; -import fr.igred.omero.exception.AccessException; -import fr.igred.omero.exception.OMEROServerError; -import fr.igred.omero.exception.ServiceException; -import fr.igred.omero.repository.DatasetWrapper; import fr.igred.omero.repository.ImageWrapper; -import fr.igred.omero.repository.ProjectWrapper; -import fr.igred.omero.roi.ROIWrapper; -import ij.IJ; import ij.ImagePlus; -import ij.WindowManager; -import ij.gui.Overlay; -import ij.gui.Roi; -import ij.io.RoiEncoder; -import ij.measure.ResultsTable; import ij.plugin.frame.RoiManager; -import ij.text.TextWindow; import loci.formats.FileStitcher; import loci.formats.FormatException; import loci.plugins.BF; import loci.plugins.in.ImportProcess; import loci.plugins.in.ImporterOptions; -import java.awt.Component; -import java.awt.Frame; -import java.io.BufferedOutputStream; -import java.io.DataOutputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.lang.invoke.MethodHandles; -import java.nio.file.Files; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.concurrent.ExecutionException; import java.util.logging.Logger; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; /** - * Runs a script over multiple images retrieved from local files or from OMERO. + * Image stored in a local file. */ -public class OMEROBatchRunner extends Thread { +public class LocalBatchImage implements BatchImage { private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName()); private static final File[] EMPTY_FILE_ARRAY = new File[0]; - private static final int[] EMPTY_INT_ARRAY = new int[0]; - private static final Pattern TITLE_AFTER_EXT = Pattern.compile("\\w+\\s?\\[?([^\\[\\]]*)]?"); - private final ScriptRunner script; - private final Client client; - private final ProgressMonitor progress; - - private final Map tables = new HashMap<>(5); - - private boolean inputOnOMERO; - private boolean saveImage; - private boolean saveROIs; - private boolean saveResults; - private boolean saveLog; - private boolean loadROIs; - private boolean clearROIs; - private boolean outputOnOMERO; - private boolean outputOnLocal; - private boolean recursive; - private long inputDatasetId; - private long outputDatasetId; - private long outputProjectId; - private String directoryIn; - private String directoryOut; - private String suffix; - - private RoiManager rm; - - private BatchListener listener; - - - public OMEROBatchRunner(ScriptRunner script, Client client) { + public LocalBatchImage(ScriptRunner script, Client client) { this(script, client, new ProgressLog(LOGGER)); } - public OMEROBatchRunner(ScriptRunner script, Client client, ProgressMonitor progress) { + public LocalBatchImage(ScriptRunner script, Client client, ProgressMonitor progress) { this.script = script; this.client = client; this.progress = progress; diff --git a/src/main/java/fr/igred/ij/io/package-info.java b/src/main/java/fr/igred/ij/io/package-info.java index b63530d..bd88ff1 100644 --- a/src/main/java/fr/igred/ij/io/package-info.java +++ b/src/main/java/fr/igred/ij/io/package-info.java @@ -18,6 +18,7 @@ * This package contains interfaces and classes meant to handle input/output, most notably images: *
    *
  • {@link fr.igred.ij.io.BatchImage} to generally handle images in batch
  • + *
  • {@link fr.igred.ij.io.LocalBatchImage} to manage local images
  • *
* It also contains {@link fr.igred.ij.io.ROIMode} to handle ROI loading. */ From f07f0114bd09f5717e000feddbf68c1d7df59bbd Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 11:27:15 +0100 Subject: [PATCH 04/33] Only keep relevant code in LocalBatchImage --- .../java/fr/igred/ij/io/LocalBatchImage.java | 878 +----------------- 1 file changed, 16 insertions(+), 862 deletions(-) diff --git a/src/main/java/fr/igred/ij/io/LocalBatchImage.java b/src/main/java/fr/igred/ij/io/LocalBatchImage.java index 7b4a72d..518324f 100644 --- a/src/main/java/fr/igred/ij/io/LocalBatchImage.java +++ b/src/main/java/fr/igred/ij/io/LocalBatchImage.java @@ -18,7 +18,6 @@ import fr.igred.omero.repository.ImageWrapper; import ij.ImagePlus; -import ij.plugin.frame.RoiManager; import loci.formats.FileStitcher; import loci.formats.FormatException; import loci.plugins.BF; @@ -43,91 +42,23 @@ public class LocalBatchImage implements BatchImage { private static final File[] EMPTY_FILE_ARRAY = new File[0]; - - public LocalBatchImage(ScriptRunner script, Client client) { - this(script, client, new ProgressLog(LOGGER)); - } - - - public LocalBatchImage(ScriptRunner script, Client client, ProgressMonitor progress) { - this.script = script; - this.client = client; - this.progress = progress; - this.directoryIn = ""; - this.suffix = ""; - this.directoryOut = null; - this.rm = null; - this.listener = null; - } - - - /** - * Generates the timestamp for current time. - * - * @return See above. - */ - private static String timestamp() { - return DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss").format(ZonedDateTime.now()); - } - - - /** - * Removes file extension from image title. - * - * @param title Image title. - * - * @return The title, without the extension. - */ - private static String removeExtension(String title) { - if (title != null) { - int index = title.lastIndexOf('.'); - if (index == 0 || index == -1) { - return title; - } else { - String afterExt = TITLE_AFTER_EXT.matcher(title.substring(index + 1)).replaceAll("$1"); - String beforeExt = title.substring(0, index); - if(beforeExt.toLowerCase().endsWith(".ome") && beforeExt.lastIndexOf('.') > 0) { - beforeExt = beforeExt.substring(0, beforeExt.lastIndexOf('.')); - } - return afterExt.isEmpty() ? beforeExt : beforeExt + "_" + afterExt; - } - } else { - return null; - } - } + private final String path; + private final Integer index; - /** - * Deletes the temp folder. - * - * @param tmpDir The temp folder. - * - * @return True if the deletion was successful. - */ - private static boolean deleteTemp(String tmpDir) { - boolean deleted = true; - File dir = new File(tmpDir); - File[] entries = dir.listFiles(); - if (entries != null) { - try { - for (File entry : entries) { - deleted &= Files.deleteIfExists(entry.toPath()); - } - deleted &= Files.deleteIfExists(dir.toPath()); - } catch (IOException e) { - IJ.error("Could not delete files: " + e.getMessage()); - } - } - return deleted; + public LocalBatchImage(String path, Integer index, boolean loadROIs) { + this.path = path; + this.index = index; } /** - * List all files contained in a directory + * List the files contained in the directory. * - * @param directory The folder to process + * @param directory The directory. + * @param recursive Whether files should be listed recursively. * - * @return The list of images paths. + * @return The list of file paths. */ private static List getFilesFromDirectory(String directory, boolean recursive) { File dir = new File(directory); @@ -152,9 +83,9 @@ private static List getFilesFromDirectory(String directory, boolean recu * @param files The list of files. * @param options The Bio-Formats importer options. * - * @return A map containing the number of images for each file. + * @return The list of images. */ - private static Map getImagesFromFiles(Collection files, ImporterOptions options) { + private static List getImagesFromFiles(Collection files, ImporterOptions options) { List used = new ArrayList<>(files.size()); Map imageFiles = new LinkedHashMap<>(files.size()); for (String file : files) { @@ -178,106 +109,6 @@ private static Map getImagesFromFiles(Collection files, } - /** - * Retrieves the list of images open after the script was run. - * - * @param inputImage The input image. - * - * @return See above. - */ - private static List getOutputImages(ImagePlus inputImage) { - ImagePlus outputImage = WindowManager.getCurrentImage(); - if (outputImage == null) { - outputImage = inputImage; - } - int ijOutputId = outputImage.getID(); - - int[] imageIds = WindowManager.getIDList(); - if (imageIds == null) { - imageIds = EMPTY_INT_ARRAY; - } - List idList = Arrays.stream(imageIds).boxed().collect(Collectors.toList()); - idList.removeIf(i -> i.equals(ijOutputId)); - idList.add(0, ijOutputId); - return idList.stream() - .map(WindowManager::getImage) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - - /** - * Retrieves the list of ROIs from an image overlay. - * - * @param imp The image ROIs are linked to. - * - * @return See above. - */ - private static List getOverlay(ImagePlus imp) { - Overlay overlay = imp.getOverlay(); - List ijRois = new ArrayList<>(0); - if (overlay != null) { - ijRois = new ArrayList<>(Arrays.asList(overlay.toArray())); - } - for (Roi roi : ijRois) roi.setImage(imp); - return ijRois; - } - - - /** - * Converts ROIs from an image overlay to OMERO ROIs. - * - * @param imp The image ROIs are linked to. - * @param property The ROI property used to group shapes in OMERO. - * - * @return A list of OMERO ROIs. - */ - private static List getROIsFromOverlay(ImagePlus imp, String property) { - List rois = new ArrayList<>(0); - if (imp != null) { - List ijRois = getOverlay(imp); - rois = ROIWrapper.fromImageJ(ijRois, property); - } - - return rois; - } - - - /** - * Saves ImageJ ROIs to a file. - * - * @param ijRois The ROIs. - * @param path The path to the file. - */ - private static void saveRoiFile(List ijRois, String path) { - try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(path))); - DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(zos))) { - RoiEncoder re = new RoiEncoder(dos); - for (int i = 0; i < ijRois.size(); i++) { - if (ijRois.get(i) != null) { - // WARNING: Prepending index does not ensure label is unique. - String label = i + "-" + ijRois.get(i).getName() + ".roi"; - zos.putNextEntry(new ZipEntry(label)); - re.write(ijRois.get(i)); - dos.flush(); - } - } - } catch (IOException e) { - IJ.error("Error while saving ROI file: " + e.getMessage()); - } - } - - - /** - * Initializes the ROI manager. - */ - private void initRoiManager() { - rm = RoiManager.getInstance2(); - if (rm == null) rm = RoiManager.getRoiManager(); - rm.setVisible(false); - } - - /** * Initializes the Bio-Formats importer options. * @@ -285,7 +116,7 @@ private void initRoiManager() { * * @throws IOException If the importer options could not be initialized. */ - private ImporterOptions initImporterOptions() throws IOException { + private static ImporterOptions initImporterOptions() throws IOException { ImporterOptions options = new ImporterOptions(); options.setStackFormat(ImporterOptions.VIEW_HYPERSTACK); options.setSwapDimensions(false); @@ -293,7 +124,6 @@ private ImporterOptions initImporterOptions() throws IOException { options.setSpecifyRanges(false); options.setShowMetadata(false); options.setShowOMEXML(false); - options.setShowROIs(loadROIs); options.setCrop(false); options.setSplitChannels(false); options.setSplitFocalPlanes(false); @@ -303,192 +133,13 @@ private ImporterOptions initImporterOptions() throws IOException { /** - * Sets the current state. - * - * @param text The text for the current state. - */ - private void setState(String text) { - if (progress != null) progress.setState(text); - } - - - /** - * Sets the current progress. - * - * @param text The text for the current progress. - */ - private void setProgress(String text) { - if (progress != null) progress.setProgress(text); - } - - - /** - * Signals the process is done. - */ - private void setDone() { - if (progress != null) progress.setDone(); - } - - - /** - * If this thread was constructed using a separate - * {@code Runnable} run object, then that - * {@code Runnable} object's {@code run} method is called; - * otherwise, this method does nothing and returns. - *

- * Subclasses of {@code Thread} should override this method. - * - * @see #start() - * @see Thread#Thread(ThreadGroup, Runnable, String) - */ - @Override - public void run() { - boolean finished = false; - if (progress instanceof ProgressDialog) { - ((Component) progress).setVisible(true); - } - - try { - if (!outputOnLocal) { - setState("Temporary directory creation..."); - directoryOut = Files.createTempDirectory("Fiji_analysis").toString(); - } - - if (inputOnOMERO) { - setState("Retrieving images from OMERO..."); - DatasetWrapper dataset = client.getDataset(inputDatasetId); - List images = dataset.getImages(client); - setState("Macro running..."); - runMacro(images); - } else { - setState("Retrieving files from input folder..."); - List files = getFilesFromDirectory(directoryIn, recursive); - setState("Macro running..."); - runMacroOnLocalImages(files); - } - setProgress(""); - uploadTables(); - - if (!outputOnLocal) { - setState("Temporary directory deletion..."); - if (!deleteTemp(directoryOut)) { - LOGGER.warning("Temp directory may not be deleted."); - } - } - finished = true; - setState(""); - setDone(); - } catch (NoSuchElementException | IOException | ServiceException | AccessException | ExecutionException e) { - finished = true; - setDone(); - setProgress("Macro cancelled"); - if (e.getMessage() != null && "Macro cancelled".equals(e.getMessage())) { - IJ.run("Close"); - } - IJ.error(e.getMessage()); - } finally { - if (!finished) { - setDone(); - setProgress("An unexpected error occurred."); - } - if (listener != null) listener.onThreadFinished(); - rm.setVisible(true); - rm.close(); - } - } - - - /** - * Deletes all owned ROIs from an image on OMERO. - * - * @param image The image on OMERO. - */ - private void deleteROIs(ImageWrapper image) { - setState("ROIs deletion from OMERO"); - try { - List rois = image.getROIs(client); - for (ROIWrapper roi : rois) { - if (roi.getOwner().getId() == client.getId()) { - client.delete(roi); - } - } - } catch (ExecutionException | OMEROServerError | ServiceException | AccessException exception) { - LOGGER.warning(exception.getMessage()); - } catch (InterruptedException e) { - LOGGER.warning(e.getMessage()); - Thread.currentThread().interrupt(); - } - } - - - /** - * Retrieves the list of ROIs from the ROI manager. - * - * @param imp The image ROIs are linked to. + * Returns null. * * @return See above. */ - private List getManagedRois(ImagePlus imp) { - List ijRois = new ArrayList<>(Arrays.asList(rm.getRoisAsArray())); - for (Roi roi : ijRois) roi.setImage(imp); - return ijRois; - } - - - /** - * Converts ROIs from the ROI Manager to OMERO ROIs. - * - * @param imp The image ROIs are linked to. - * @param property The ROI property used to group shapes in OMERO. - * - * @return A list of OMERO ROIs. - */ - private List getROIsFromManager(ImagePlus imp, String property) { - List rois = new ArrayList<>(0); - if (imp != null) { - List ijRois = getManagedRois(imp); - rois = ROIWrapper.fromImageJ(ijRois, property); - } - - return rois; - } - - - /** - * Runs a macro on images from OMERO and saves the results. - * - * @param images List of images on OMERO. - */ - void runMacro(List images) { - String property = ROIWrapper.IJ_PROPERTY; - WindowManager.closeAllWindows(); - int index = 0; - for (ImageWrapper image : images) { - setProgress("Image " + (index + 1) + "/" + images.size()); - long inputImageId = image.getId(); - - // Open image from OMERO - ImagePlus imp = openImage(image); - // If image could not be loaded, continue to next image. - if (imp != null) { - // Initialize ROI Manager - initRoiManager(); - - // Load ROIs - if (loadROIs) loadROIs(image, imp, false); - - imp.show(); - - // Analyse the image - script.setImage(imp); - script.run(); - - imp.changes = false; // Prevent "Save Changes?" dialog - save(imp, inputImageId, property); - } - closeWindows(); - index++; - } + @Override + public ImageWrapper getImageWrapper() { + return null; } @@ -538,501 +189,4 @@ void runMacroOnLocalImages(Collection files) throws IOException { } } - - /** - * Opens an image from OMERO. - * - * @param image An OMERO image. - * - * @return An ImagePlus. - */ - private ImagePlus openImage(ImageWrapper image) { - setState("Opening image from OMERO..."); - ImagePlus imp = null; - try { - imp = image.toImagePlus(client); - // Store image "annotate" permissions as a property in the ImagePlus object - imp.setProp("Annotatable", String.valueOf(image.canAnnotate())); - } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Could not load image: " + e.getMessage()); - } - return imp; - } - - - /** - * Loads ROIs from an image in OMERO into ImageJ. - * - * @param image The OMERO image. - * @param imp The image in ImageJ ROIs should be linked to. - * @param toOverlay Whether the ROIs should be loaded to the ROI Manager (false) or the overlay (true). - */ - private void loadROIs(ImageWrapper image, ImagePlus imp, boolean toOverlay) { - List ijRois = new ArrayList<>(0); - try { - ijRois = ROIWrapper.toImageJ(image.getROIs(client)); - } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Could not load ROIs: " + e.getMessage()); - } - if (toOverlay) { - Overlay overlay = imp.getOverlay(); - if (overlay != null) { - overlay.clear(); - } else { - overlay = new Overlay(); - } - for (Roi ijRoi : ijRois) { - ijRoi.setImage(imp); - overlay.add(ijRoi, ijRoi.getName()); - } - } else { - rm.reset(); // Reset ROI manager to clear previous ROIs - for (Roi ijRoi : ijRois) { - ijRoi.setImage(imp); - rm.addRoi(ijRoi); - } - } - } - - - /** - * Saves the images, results and ROIs. - * - * @param inputImage The input image in ImageJ. - * @param omeroInputId The OMERO image input ID. - * @param property The ROI property used to group shapes in OMERO. - */ - private void save(ImagePlus inputImage, Long omeroInputId, String property) { - String inputTitle = removeExtension(inputImage.getTitle()); - - Long omeroOutputId = omeroInputId; - List outputs = getOutputImages(inputImage); - - ImagePlus outputImage = inputImage; - if (!outputs.isEmpty()) outputImage = outputs.get(0); - - // If input image is expected as output for ROIs on OMERO but is not annotable, import it. - boolean annotable = Boolean.parseBoolean(inputImage.getProp("Annotable")); - boolean outputIsNotInput = !inputImage.equals(outputImage); - if (!outputOnOMERO || !saveROIs || annotable || outputIsNotInput) { - outputs.removeIf(inputImage::equals); - } - - if (saveImage) { - if (outputs.isEmpty()) LOGGER.info("Warning: there is no new image."); - List outputIds = new ArrayList<>(outputs.size()); - outputs.forEach(imp -> outputIds.addAll(saveImage(imp, property))); - if (!outputIds.isEmpty() && outputIsNotInput) { - omeroOutputId = outputIds.get(0); - } - } - - if (saveROIs) { - if (!saveImage) saveOverlay(outputImage, omeroOutputId, inputTitle, property); - saveROIManager(outputImage, omeroOutputId, inputTitle, property); - } - if (saveResults) saveResults(outputImage, omeroOutputId, inputTitle, property); - if (saveLog) saveLog(omeroOutputId, inputTitle); - - for (ImagePlus imp : outputs) { - imp.changes = false; - imp.close(); - } - } - - - /** - * Saves an image. - * - * @param image The image to save. - * @param property The ROI property to group shapes in OMERO. - * - * @return The OMERO IDs of the (possibly) uploaded image. Should be empty or contain one value. - */ - private List saveImage(ImagePlus image, String property) { - List ids = new ArrayList<>(0); - String title = removeExtension(image.getTitle()); - String path = directoryOut + File.separator + title + suffix + ".tif"; - IJ.saveAsTiff(image, path); - if (outputOnOMERO) { - try { - setState("Import on OMERO..."); - DatasetWrapper dataset = client.getDataset(outputDatasetId); - ids = dataset.importImage(client, path); - if (saveROIs && !ids.isEmpty()) { - saveOverlay(image, ids.get(0), title, property); - } - } catch (AccessException | ServiceException | OMEROServerError | ExecutionException e) { - IJ.error("Could not import image: " + e.getMessage()); - } - } - return ids; - } - - - /** - * Saves the ROIs from an image overlay in ImageJ. - * - * @param imp The image. - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. - * @param property The ROI property used to group shapes on OMERO. - */ - private void saveOverlay(ImagePlus imp, Long imageId, String title, String property) { - if (outputOnLocal) { // local save - setState("Saving overlay ROIs..."); - String path = directoryOut + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; - List ijRois = getOverlay(imp); - saveRoiFile(ijRois, path); - } - if (outputOnOMERO && imageId != null) { // save on Omero - List rois = getROIsFromOverlay(imp, property); - try { - ImageWrapper image = client.getImage(imageId); - if (clearROIs) { - deleteROIs(image); - } - setState("Saving overlay ROIs on OMERO..."); - image.saveROIs(client, rois); - loadROIs(image, imp, true); // reload ROIs - } catch (ServiceException | AccessException | ExecutionException e) { - IJ.error("Could not import overlay ROIs to OMERO: " + e.getMessage()); - } - } - } - - - /** - * Saves the ROIs from the ROI Manager (for an image). - * - * @param imp The image. - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. - * @param property The ROI property used to group shapes on OMERO. - */ - private void saveROIManager(ImagePlus imp, Long imageId, String title, String property) { - if (outputOnLocal) { // local save - setState("Saving ROIs..."); - String path = directoryOut + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; - List ijRois = getManagedRois(imp); - saveRoiFile(ijRois, path); - } - if (outputOnOMERO && imageId != null) { // save on Omero - List rois = getROIsFromManager(imp, property); - try { - ImageWrapper image = client.getImage(imageId); - if (clearROIs) { - deleteROIs(image); - } - setState("Saving ROIs on OMERO..."); - image.saveROIs(client, rois); - loadROIs(image, imp, false); // reload ROIs - } catch (ServiceException | AccessException | ExecutionException e) { - IJ.error("Could not import ROIs to OMERO: " + e.getMessage()); - } - } - } - - - /** - * Saves the results (linked to an image). - * - * @param imp The image. - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. - * @param property The ROI property used to group shapes on OMERO. - */ - private void saveResults(ImagePlus imp, Long imageId, String title, String property) { - List ijRois = getOverlay(imp); - ijRois.addAll(getManagedRois(imp)); - - setState("Saving results files..."); - String[] candidates = WindowManager.getNonImageTitles(); - List results = Arrays.stream(candidates) - .map(ResultsTable::getResultsTable) - .collect(Collectors.toList()); - results.add(0, ResultsTable.getResultsTable()); - Map processed = new HashMap<>(results.size()); - for (ResultsTable rt : results) { - if (rt != null) { - String name = rt.getTitle(); - if (!Boolean.TRUE.equals(processed.get(name)) && rt.getHeadings().length > 0) { - String path = directoryOut + File.separator + name + "_" + title + "_" + timestamp() + ".csv"; - rt.save(path); - if (outputOnOMERO) { - appendTable(rt, imageId, ijRois, property); - uploadFile(imageId, path); - } - rt.reset(); - processed.put(name, true); - } - } - } - } - - - /** - * Saves the log. - * - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. - */ - private void saveLog(Long imageId, String title) { - String path = directoryOut + File.separator + title + "_log.txt"; - IJ.selectWindow("Log"); - IJ.saveAs("txt", path); - if (outputOnOMERO) uploadFile(imageId, path); - } - - - /** - * Uploads a file to an image on OMERO. - * - * @param imageId The image ID on OMERO. - * @param path The path to the file. - */ - private void uploadFile(Long imageId, String path) { - if (imageId != null) { - try { - setState("Uploading results files..."); - ImageWrapper image = client.getImage(imageId); - image.addFile(client, new File(path)); - } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Error adding file to image:" + e.getMessage()); - } catch (InterruptedException e) { - IJ.error("Error adding file to image:" + e.getMessage()); - Thread.currentThread().interrupt(); - } - } - } - - - /** - * Adds the current results to the corresponding table. - * - * @param results The results table. - * @param imageId The image ID on OMERO. - * @param ijRois The ROIs in ImageJ. - * @param property The ROI property used to group shapes on OMERO. - */ - private void appendTable(ResultsTable results, Long imageId, List ijRois, String property) { - String resultsName = results.getTitle(); - TableWrapper table = tables.get(resultsName); - try { - if (table == null) { - tables.put(resultsName, new TableWrapper(client, results, imageId, ijRois, property)); - } else { - table.addRows(client, results, imageId, ijRois, property); - } - } catch (ServiceException | AccessException | ExecutionException e) { - IJ.error("Could not create or append table: " + e.getMessage()); - } - } - - - /** - * Upload the tables to OMERO. - */ - private void uploadTables() { - if (outputOnOMERO && saveResults) { - setState("Uploading tables..."); - try { - ProjectWrapper project = client.getProject(outputProjectId); - for (Map.Entry entry : tables.entrySet()) { - String name = entry.getKey(); - TableWrapper table = entry.getValue(); - String newName; - if (name == null || name.isEmpty()) newName = timestamp() + "_" + table.getName(); - else newName = timestamp() + "_" + name; - table.setName(newName); - project.addTable(client, table); - String path = directoryOut + File.separator + newName + ".csv"; - table.saveAs(path, 'c'); - project.addFile(client, new File(path)); - } - } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Could not save table: " + e.getMessage()); - } catch (IOException e) { - IJ.error("Could not save table as file: " + e.getMessage()); - } catch (InterruptedException e) { - IJ.error("Could not upload CSV to project: " + e.getMessage()); - Thread.currentThread().interrupt(); - } - } - } - - - /** - * Closes all open windows in ImageJ. - */ - private void closeWindows() { - for (Frame frame : WindowManager.getNonImageWindows()) { - if (frame instanceof TextWindow) { - ((TextWindow) frame).close(false); - } - } - rm.reset(); - WindowManager.closeAllWindows(); - } - - - public Client getClient() { - return client; - } - - - public long getOutputProjectId() { - return outputProjectId; - } - - - public void setOutputProjectId(Long outputProjectId) { - if (outputProjectId != null) this.outputProjectId = outputProjectId; - } - - - public long getOutputDatasetId() { - return outputDatasetId; - } - - - public void setOutputDatasetId(Long outputDatasetId) { - if (outputDatasetId != null) this.outputDatasetId = outputDatasetId; - } - - - public long getInputDatasetId() { - return inputDatasetId; - } - - - public void setInputDatasetId(Long inputDatasetId) { - if (inputDatasetId != null) this.inputDatasetId = inputDatasetId; - } - - - public boolean shouldSaveROIs() { - return saveROIs; - } - - - public void setSaveROIs(boolean saveROIs) { - this.saveROIs = saveROIs; - } - - - public boolean shouldSaveResults() { - return saveResults; - } - - - public void setSaveResults(boolean saveResults) { - this.saveResults = saveResults; - } - - - public boolean isInputOnOMERO() { - return inputOnOMERO; - } - - - public void setInputOnOMERO(boolean inputOnOMERO) { - this.inputOnOMERO = inputOnOMERO; - } - - - public boolean shouldSaveImage() { - return saveImage; - } - - - public void setSaveImage(boolean saveImage) { - this.saveImage = saveImage; - } - - - public boolean shouldLoadROIs() { - return loadROIs; - } - - - public void setLoadROIS(boolean loadROIs) { - this.loadROIs = loadROIs; - } - - - public boolean shouldClearROIs() { - return clearROIs; - } - - - public void setClearROIS(boolean clearROIs) { - this.clearROIs = clearROIs; - } - - - public String getDirectoryIn() { - return directoryIn; - } - - - public void setDirectoryIn(String directoryIn) { - this.directoryIn = directoryIn; - } - - - public String getDirectoryOut() { - return directoryOut; - } - - - public void setDirectoryOut(String directoryOut) { - this.directoryOut = directoryOut; - } - - - public String getSuffix() { - return suffix; - } - - - public void setSuffix(String suffix) { - this.suffix = suffix; - } - - - public boolean isOutputOnOMERO() { - return outputOnOMERO; - } - - - public void setOutputOnOMERO(boolean outputOnOMERO) { - this.outputOnOMERO = outputOnOMERO; - } - - - public boolean isOutputOnLocal() { - return outputOnLocal; - } - - - public void setOutputOnLocal(boolean outputOnLocal) { - this.outputOnLocal = outputOnLocal; - } - - - public void setSaveLog(boolean saveLog) { - this.saveLog = saveLog; - } - - - public void setListener(BatchListener listener) { - this.listener = listener; - } - - - public void setRecursive(boolean recursive) { - this.recursive = recursive; - } - } From 0ffeb26909796ef78c9c513ace39840c27c5cb10 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 10:50:30 +0100 Subject: [PATCH 05/33] Add BatchImage interface --- src/main/java/fr/igred/ij/io/BatchImage.java | 52 +++++++++++++++ src/main/java/fr/igred/ij/io/ROIMode.java | 64 +++++++++++++++++++ .../java/fr/igred/ij/io/package-info.java | 24 +++++++ 3 files changed, 140 insertions(+) create mode 100644 src/main/java/fr/igred/ij/io/BatchImage.java create mode 100644 src/main/java/fr/igred/ij/io/ROIMode.java create mode 100644 src/main/java/fr/igred/ij/io/package-info.java diff --git a/src/main/java/fr/igred/ij/io/BatchImage.java b/src/main/java/fr/igred/ij/io/BatchImage.java new file mode 100644 index 0000000..8e67b44 --- /dev/null +++ b/src/main/java/fr/igred/ij/io/BatchImage.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021-2023 MICA & GReD + * + * 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 2 of the License, or (at your option) any later + * version. + + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin + * Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package fr.igred.ij.io; + +import fr.igred.omero.repository.ImageWrapper; +import ij.ImagePlus; + +/** + * Interface to open images and retrieve the corresponding image on OMERO, if applicable. + */ +public interface BatchImage { + + /** + * Returns the related ImageWrapper, or null if there is none. + * + * @return See above. + */ + ImageWrapper getImageWrapper(); + + /** + * Opens the image and returns the corresponding ImagePlus. + * + * @param mode The mode used to load ROIs. + * + * @return See above. + */ + ImagePlus getImagePlus(ROIMode mode); + + /** + * Opens the image and returns the corresponding ImagePlus, with no ROI. + * + * @return See above. + */ + default ImagePlus getImagePlus() { + return getImagePlus(ROIMode.DO_NOT_LOAD); + } + +} diff --git a/src/main/java/fr/igred/ij/io/ROIMode.java b/src/main/java/fr/igred/ij/io/ROIMode.java new file mode 100644 index 0000000..2c3e32d --- /dev/null +++ b/src/main/java/fr/igred/ij/io/ROIMode.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021-2023 MICA & GReD + * + * 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 2 of the License, or (at your option) any later + * version. + + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin + * Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package fr.igred.ij.io; + + +import loci.plugins.in.ImporterOptions; + +/** + * Modes used to load ROIs. + */ +public enum ROIMode { + /** + * Do not load ROIs (empty String for ImporterOptions). + */ + DO_NOT_LOAD(""), + /** + * Load ROIs in the ROI Manager. + */ + MANAGER(ImporterOptions.ROIS_MODE_MANAGER), + /** + * Load ROIs as overlay. + */ + OVERLAY(ImporterOptions.ROIS_MODE_OVERLAY); + + /** + * ROI mode String value for ImporterOptions. + */ + private final String value; + + + /** + * Constructor of the ROIMode enum. + * + * @param value The ROI mode String value for ImporterOptions. + */ + ROIMode(String value) { + this.value = value; + } + + + /** + * Returns the ROI mode String value for ImporterOptions. + * + * @return See above. + */ + @Override + public String toString() { + return value; + } +} diff --git a/src/main/java/fr/igred/ij/io/package-info.java b/src/main/java/fr/igred/ij/io/package-info.java new file mode 100644 index 0000000..b63530d --- /dev/null +++ b/src/main/java/fr/igred/ij/io/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021-2023 MICA & GReD + * + * 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 2 of the License, or (at your option) any later + * version. + + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin + * Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +/** + * This package contains interfaces and classes meant to handle input/output, most notably images: + *

    + *
  • {@link fr.igred.ij.io.BatchImage} to generally handle images in batch
  • + *
+ * It also contains {@link fr.igred.ij.io.ROIMode} to handle ROI loading. + */ +package fr.igred.ij.io; \ No newline at end of file From 215c98c9795c64815509a609330a5923dd226f17 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 11:44:50 +0100 Subject: [PATCH 06/33] Put appropriate methods in LocalBatchImage --- .../java/fr/igred/ij/io/LocalBatchImage.java | 94 ++++++++----------- 1 file changed, 38 insertions(+), 56 deletions(-) diff --git a/src/main/java/fr/igred/ij/io/LocalBatchImage.java b/src/main/java/fr/igred/ij/io/LocalBatchImage.java index 518324f..9578cc5 100644 --- a/src/main/java/fr/igred/ij/io/LocalBatchImage.java +++ b/src/main/java/fr/igred/ij/io/LocalBatchImage.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 @@ -46,7 +46,7 @@ public class LocalBatchImage implements BatchImage { private final Integer index; - public LocalBatchImage(String path, Integer index, boolean loadROIs) { + public LocalBatchImage(String path, Integer index) { this.path = path; this.index = index; } @@ -60,17 +60,15 @@ public LocalBatchImage(String path, Integer index, boolean loadROIs) { * * @return The list of file paths. */ - private static List getFilesFromDirectory(String directory, boolean recursive) { - File dir = new File(directory); - File[] files = dir.listFiles(); + private static List listFiles(File directory, boolean recursive) { + File[] files = directory.listFiles(); if (files == null) files = EMPTY_FILE_ARRAY; List paths = new ArrayList<>(files.length); for (File file : files) { - String path = file.getAbsolutePath(); if (!file.isDirectory()) { - paths.add(path); + paths.add(file.getAbsolutePath()); } else if (recursive) { - paths.addAll(getFilesFromDirectory(path, true)); + paths.addAll(listFiles(file, true)); } } return paths; @@ -78,16 +76,21 @@ private static List getFilesFromDirectory(String directory, boolean recu /** - * Retrieves the images in a list of files using Bio-Formats. + * Creates a list of images to be opened, contained in the specified directory. * - * @param files The list of files. - * @param options The Bio-Formats importer options. + * @param directory The directory. + * @param recursive Whether files should be listed recursively. * * @return The list of images. + * + * @throws IOException ImporterOptions could not be instantiated. */ - private static List getImagesFromFiles(Collection files, ImporterOptions options) { + public static List listImages(String directory, boolean recursive) throws IOException { + ImporterOptions options = initImporterOptions(); + List batchImages = new LinkedList<>(); + File dir = new File(directory); + List files = listFiles(dir, recursive); List used = new ArrayList<>(files.size()); - Map imageFiles = new LinkedHashMap<>(files.size()); for (String file : files) { if (!used.contains(file)) { // Open the image @@ -99,13 +102,15 @@ private static List getImagesFromFiles(Collection files, Imp FileStitcher fs = process.getFileStitcher(); if (fs != null) used = Arrays.asList(fs.getUsedFiles()); else used.add(file); - imageFiles.put(file, n); + for (int i = 0; i < n; i++) { + batchImages.add(new LocalBatchImage(file, i)); + } } catch (IOException | FormatException e) { - LOGGER.info(e.getMessage()); + LOGGER.severe(e.getMessage()); } } } - return imageFiles; + return batchImages; } @@ -144,49 +149,26 @@ public ImageWrapper getImageWrapper() { /** - * Runs a macro on local files and saves the results. - * - * @param files List of image files. + * Opens the image and returns the corresponding ImagePlus. * - * @throws IOException A problem occurred reading a file. + * @return See above. */ - void runMacroOnLocalImages(Collection files) throws IOException { - String property = ROIWrapper.IJ_PROPERTY; - WindowManager.closeAllWindows(); - - ImporterOptions options = initImporterOptions(); - Map imageFiles = getImagesFromFiles(files, options); - int nFile = 1; - for (Map.Entry entry : imageFiles.entrySet()) { - int n = entry.getValue(); - options.setId(entry.getKey()); - for (int i = 0; i < n; i++) { - String msg = String.format("File %d/%d, image %d/%d", nFile, imageFiles.size(), i + 1, n); - setProgress(msg); - options.setSeriesOn(i, true); - try { - ImagePlus[] imps = BF.openImagePlus(options); - ImagePlus imp = imps[0]; - imp.show(); - - // Initialize ROI Manager - initRoiManager(); - - // Analyse the image - script.setImage(imp); - script.run(); - - // Save and Close the various components - imp.changes = false; // Prevent "Save Changes?" dialog - save(imp, null, property); - } catch (FormatException e) { - IJ.error(e.getMessage()); - } - closeWindows(); - options.setSeriesOn(i, false); - } - nFile++; + @Override + public ImagePlus getImagePlus(ROIMode mode) { + ImagePlus imp = null; + boolean loadROIs = !mode.toString().isEmpty(); + try { + ImporterOptions options = initImporterOptions(); + options.setShowROIs(loadROIs); + options.setROIsMode(mode.toString()); + options.setId(path); + options.setSeriesOn(index, true); + ImagePlus[] imps = BF.openImagePlus(options); + imp = imps[0]; + } catch (FormatException | IOException e) { + LOGGER.severe(e.getMessage()); } + return imp; } } From 7b5ecda0001514e7217b67d4d3249066b0a592a2 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 11:46:50 +0100 Subject: [PATCH 07/33] Rename OMEROBatchRunner.java to OMEROBatchImage.java --- .../ij/{macro/OMEROBatchRunner.java => io/OMEROBatchImage.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/java/fr/igred/ij/{macro/OMEROBatchRunner.java => io/OMEROBatchImage.java} (99%) diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java similarity index 99% rename from src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java rename to src/main/java/fr/igred/ij/io/OMEROBatchImage.java index ebf2f77..bea1c2f 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java @@ -14,7 +14,7 @@ * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin * Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package fr.igred.ij.macro; +package fr.igred.ij.io; import fr.igred.ij.gui.ProgressDialog; import fr.igred.omero.Client; From be33c7c1bd1984537405361aa725044e673bb57e Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 14:17:05 +0100 Subject: [PATCH 08/33] Remove methods from OMEROBatchRunner --- .../fr/igred/ij/macro/OMEROBatchRunner.java | 257 ++---------------- 1 file changed, 26 insertions(+), 231 deletions(-) diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index ebf2f77..ab660c1 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -17,6 +17,8 @@ package fr.igred.ij.macro; import fr.igred.ij.gui.ProgressDialog; +import fr.igred.ij.io.BatchImage; +import fr.igred.ij.io.ROIMode; import fr.igred.omero.Client; import fr.igred.omero.annotations.TableWrapper; import fr.igred.omero.exception.AccessException; @@ -35,11 +37,6 @@ import ij.measure.ResultsTable; import ij.plugin.frame.RoiManager; import ij.text.TextWindow; -import loci.formats.FileStitcher; -import loci.formats.FormatException; -import loci.plugins.BF; -import loci.plugins.in.ImportProcess; -import loci.plugins.in.ImporterOptions; import java.awt.Component; import java.awt.Frame; @@ -54,12 +51,9 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.logging.Logger; @@ -75,31 +69,27 @@ public class OMEROBatchRunner extends Thread { private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName()); - private static final File[] EMPTY_FILE_ARRAY = new File[0]; private static final int[] EMPTY_INT_ARRAY = new int[0]; private static final Pattern TITLE_AFTER_EXT = Pattern.compile("\\w+\\s?\\[?([^\\[\\]]*)]?"); + private final List images; private final ScriptRunner script; private final Client client; private final ProgressMonitor progress; private final Map tables = new HashMap<>(5); - private boolean inputOnOMERO; + private boolean loadROIs; private boolean saveImage; private boolean saveROIs; private boolean saveResults; private boolean saveLog; - private boolean loadROIs; private boolean clearROIs; private boolean outputOnOMERO; private boolean outputOnLocal; - private boolean recursive; - private long inputDatasetId; private long outputDatasetId; private long outputProjectId; - private String directoryIn; private String directoryOut; private String suffix; @@ -107,17 +97,16 @@ public class OMEROBatchRunner extends Thread { private BatchListener listener; - - public OMEROBatchRunner(ScriptRunner script, Client client) { - this(script, client, new ProgressLog(LOGGER)); + public OMEROBatchRunner(ScriptRunner script, List images, Client client) { + this(script, images, client, new ProgressLog(LOGGER)); } - public OMEROBatchRunner(ScriptRunner script, Client client, ProgressMonitor progress) { + public OMEROBatchRunner(ScriptRunner script, List images, Client client, ProgressMonitor progress) { this.script = script; + this.images = new ArrayList<>(images); this.client = client; this.progress = progress; - this.directoryIn = ""; this.suffix = ""; this.directoryOut = null; this.rm = null; @@ -186,62 +175,6 @@ private static boolean deleteTemp(String tmpDir) { } - /** - * List all files contained in a directory - * - * @param directory The folder to process - * - * @return The list of images paths. - */ - private static List getFilesFromDirectory(String directory, boolean recursive) { - File dir = new File(directory); - File[] files = dir.listFiles(); - if (files == null) files = EMPTY_FILE_ARRAY; - List paths = new ArrayList<>(files.length); - for (File file : files) { - String path = file.getAbsolutePath(); - if (!file.isDirectory()) { - paths.add(path); - } else if (recursive) { - paths.addAll(getFilesFromDirectory(path, true)); - } - } - return paths; - } - - - /** - * Retrieves the images in a list of files using Bio-Formats. - * - * @param files The list of files. - * @param options The Bio-Formats importer options. - * - * @return A map containing the number of images for each file. - */ - private static Map getImagesFromFiles(Collection files, ImporterOptions options) { - List used = new ArrayList<>(files.size()); - Map imageFiles = new LinkedHashMap<>(files.size()); - for (String file : files) { - if (!used.contains(file)) { - // Open the image - options.setId(file); - ImportProcess process = new ImportProcess(options); - try { - process.execute(); - int n = process.getSeriesCount(); - FileStitcher fs = process.getFileStitcher(); - if (fs != null) used = Arrays.asList(fs.getUsedFiles()); - else used.add(file); - imageFiles.put(file, n); - } catch (IOException | FormatException e) { - LOGGER.info(e.getMessage()); - } - } - } - return imageFiles; - } - - /** * Retrieves the list of images open after the script was run. * @@ -342,30 +275,6 @@ private void initRoiManager() { } - /** - * Initializes the Bio-Formats importer options. - * - * @return See above. - * - * @throws IOException If the importer options could not be initialized. - */ - private ImporterOptions initImporterOptions() throws IOException { - ImporterOptions options = new ImporterOptions(); - options.setStackFormat(ImporterOptions.VIEW_HYPERSTACK); - options.setSwapDimensions(false); - options.setOpenAllSeries(false); - options.setSpecifyRanges(false); - options.setShowMetadata(false); - options.setShowOMEXML(false); - options.setShowROIs(loadROIs); - options.setCrop(false); - options.setSplitChannels(false); - options.setSplitFocalPlanes(false); - options.setSplitTimepoints(false); - return options; - } - - /** * Sets the current state. * @@ -418,18 +327,8 @@ public void run() { directoryOut = Files.createTempDirectory("Fiji_analysis").toString(); } - if (inputOnOMERO) { - setState("Retrieving images from OMERO..."); - DatasetWrapper dataset = client.getDataset(inputDatasetId); - List images = dataset.getImages(client); - setState("Macro running..."); - runMacro(images); - } else { - setState("Retrieving files from input folder..."); - List files = getFilesFromDirectory(directoryIn, recursive); - setState("Macro running..."); - runMacroOnLocalImages(files); - } + setState("Macro running..."); + runMacro(); setProgress(""); uploadTables(); @@ -442,7 +341,7 @@ public void run() { finished = true; setState(""); setDone(); - } catch (NoSuchElementException | IOException | ServiceException | AccessException | ExecutionException e) { + } catch (IOException e) { finished = true; setDone(); setProgress("Macro cancelled"); @@ -519,31 +418,30 @@ private List getROIsFromManager(ImagePlus imp, String property) { /** - * Runs a macro on images from OMERO and saves the results. - * - * @param images List of images on OMERO. + * Runs a macro on images and saves the results. */ - void runMacro(List images) { + void runMacro() { String property = ROIWrapper.IJ_PROPERTY; WindowManager.closeAllWindows(); + + // Initialize ROI Manager + initRoiManager(); + ROIMode roiMode = ROIMode.DO_NOT_LOAD; + if (loadROIs) { + roiMode = ROIMode.MANAGER; + } + int index = 0; - for (ImageWrapper image : images) { + for (BatchImage image : images) { setProgress("Image " + (index + 1) + "/" + images.size()); - long inputImageId = image.getId(); - - // Open image from OMERO - ImagePlus imp = openImage(image); + ImagePlus imp = image.getImagePlus(roiMode); // If image could not be loaded, continue to next image. if (imp != null) { - // Initialize ROI Manager - initRoiManager(); - - // Load ROIs - if (loadROIs) loadROIs(image, imp, false); - + ImageWrapper imageWrapper = image.getImageWrapper(); + Long inputImageId = imageWrapper != null ? imageWrapper.getId() : null; imp.show(); - // Analyse the image + // Process the image script.setImage(imp); script.run(); @@ -556,74 +454,6 @@ void runMacro(List images) { } - /** - * Runs a macro on local files and saves the results. - * - * @param files List of image files. - * - * @throws IOException A problem occurred reading a file. - */ - void runMacroOnLocalImages(Collection files) throws IOException { - String property = ROIWrapper.IJ_PROPERTY; - WindowManager.closeAllWindows(); - - ImporterOptions options = initImporterOptions(); - Map imageFiles = getImagesFromFiles(files, options); - int nFile = 1; - for (Map.Entry entry : imageFiles.entrySet()) { - int n = entry.getValue(); - options.setId(entry.getKey()); - for (int i = 0; i < n; i++) { - String msg = String.format("File %d/%d, image %d/%d", nFile, imageFiles.size(), i + 1, n); - setProgress(msg); - options.setSeriesOn(i, true); - try { - ImagePlus[] imps = BF.openImagePlus(options); - ImagePlus imp = imps[0]; - imp.show(); - - // Initialize ROI Manager - initRoiManager(); - - // Analyse the image - script.setImage(imp); - script.run(); - - // Save and Close the various components - imp.changes = false; // Prevent "Save Changes?" dialog - save(imp, null, property); - } catch (FormatException e) { - IJ.error(e.getMessage()); - } - closeWindows(); - options.setSeriesOn(i, false); - } - nFile++; - } - } - - - /** - * Opens an image from OMERO. - * - * @param image An OMERO image. - * - * @return An ImagePlus. - */ - private ImagePlus openImage(ImageWrapper image) { - setState("Opening image from OMERO..."); - ImagePlus imp = null; - try { - imp = image.toImagePlus(client); - // Store image "annotate" permissions as a property in the ImagePlus object - imp.setProp("Annotatable", String.valueOf(image.canAnnotate())); - } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Could not load image: " + e.getMessage()); - } - return imp; - } - - /** * Loads ROIs from an image in OMERO into ImageJ. * @@ -965,16 +795,6 @@ public void setOutputDatasetId(Long outputDatasetId) { } - public long getInputDatasetId() { - return inputDatasetId; - } - - - public void setInputDatasetId(Long inputDatasetId) { - if (inputDatasetId != null) this.inputDatasetId = inputDatasetId; - } - - public boolean shouldSaveROIs() { return saveROIs; } @@ -995,16 +815,6 @@ public void setSaveResults(boolean saveResults) { } - public boolean isInputOnOMERO() { - return inputOnOMERO; - } - - - public void setInputOnOMERO(boolean inputOnOMERO) { - this.inputOnOMERO = inputOnOMERO; - } - - public boolean shouldSaveImage() { return saveImage; } @@ -1035,16 +845,6 @@ public void setClearROIS(boolean clearROIs) { } - public String getDirectoryIn() { - return directoryIn; - } - - - public void setDirectoryIn(String directoryIn) { - this.directoryIn = directoryIn; - } - - public String getDirectoryOut() { return directoryOut; } @@ -1094,9 +894,4 @@ public void setListener(BatchListener listener) { this.listener = listener; } - - public void setRecursive(boolean recursive) { - this.recursive = recursive; - } - } From 634d4a0b91ebfd73116514a8d0d581a2307d72db Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 11:50:43 +0100 Subject: [PATCH 09/33] Rename OMEROBatchRunner class to OMEROBatchImage --- .../java/fr/igred/ij/io/OMEROBatchImage.java | 53 +++---------------- .../java/fr/igred/ij/io/package-info.java | 1 + 2 files changed, 7 insertions(+), 47 deletions(-) diff --git a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java index bea1c2f..e4af77d 100644 --- a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java +++ b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java @@ -16,73 +16,32 @@ */ package fr.igred.ij.io; -import fr.igred.ij.gui.ProgressDialog; import fr.igred.omero.Client; -import fr.igred.omero.annotations.TableWrapper; import fr.igred.omero.exception.AccessException; -import fr.igred.omero.exception.OMEROServerError; import fr.igred.omero.exception.ServiceException; -import fr.igred.omero.repository.DatasetWrapper; import fr.igred.omero.repository.ImageWrapper; -import fr.igred.omero.repository.ProjectWrapper; import fr.igred.omero.roi.ROIWrapper; -import ij.IJ; import ij.ImagePlus; -import ij.WindowManager; import ij.gui.Overlay; import ij.gui.Roi; -import ij.io.RoiEncoder; -import ij.measure.ResultsTable; import ij.plugin.frame.RoiManager; -import ij.text.TextWindow; -import loci.formats.FileStitcher; -import loci.formats.FormatException; -import loci.plugins.BF; -import loci.plugins.in.ImportProcess; -import loci.plugins.in.ImporterOptions; - -import java.awt.Component; -import java.awt.Frame; -import java.io.BufferedOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; + import java.lang.invoke.MethodHandles; -import java.nio.file.Files; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.logging.Logger; -import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; /** - * Runs a script over multiple images retrieved from local files or from OMERO. + * Image from OMERO. */ -public class OMEROBatchRunner extends Thread { +public class OMEROBatchImage implements BatchImage { private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName()); - private static final File[] EMPTY_FILE_ARRAY = new File[0]; - private static final int[] EMPTY_INT_ARRAY = new int[0]; - - private static final Pattern TITLE_AFTER_EXT = Pattern.compile("\\w+\\s?\\[?([^\\[\\]]*)]?"); - - private final ScriptRunner script; private final Client client; - private final ProgressMonitor progress; private final Map tables = new HashMap<>(5); @@ -108,12 +67,12 @@ public class OMEROBatchRunner extends Thread { private BatchListener listener; - public OMEROBatchRunner(ScriptRunner script, Client client) { + public OMEROBatchImage(ScriptRunner script, Client client) { this(script, client, new ProgressLog(LOGGER)); } - public OMEROBatchRunner(ScriptRunner script, Client client, ProgressMonitor progress) { + public OMEROBatchImage(ScriptRunner script, Client client, ProgressMonitor progress) { this.script = script; this.client = client; this.progress = progress; @@ -150,7 +109,7 @@ private static String removeExtension(String title) { } else { String afterExt = TITLE_AFTER_EXT.matcher(title.substring(index + 1)).replaceAll("$1"); String beforeExt = title.substring(0, index); - if(beforeExt.toLowerCase().endsWith(".ome") && beforeExt.lastIndexOf('.') > 0) { + if (beforeExt.toLowerCase().endsWith(".ome") && beforeExt.lastIndexOf('.') > 0) { beforeExt = beforeExt.substring(0, beforeExt.lastIndexOf('.')); } return afterExt.isEmpty() ? beforeExt : beforeExt + "_" + afterExt; diff --git a/src/main/java/fr/igred/ij/io/package-info.java b/src/main/java/fr/igred/ij/io/package-info.java index b63530d..4fe3478 100644 --- a/src/main/java/fr/igred/ij/io/package-info.java +++ b/src/main/java/fr/igred/ij/io/package-info.java @@ -18,6 +18,7 @@ * This package contains interfaces and classes meant to handle input/output, most notably images: *
    *
  • {@link fr.igred.ij.io.BatchImage} to generally handle images in batch
  • + *
  • {@link fr.igred.ij.io.OMEROBatchImage} to manage images from OMERO
  • *
* It also contains {@link fr.igred.ij.io.ROIMode} to handle ROI loading. */ From e05aae76362d8baa1ab8c995e3f1f53dfe70bb79 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 13:48:43 +0100 Subject: [PATCH 10/33] Only keep relevant code in OMEROBatchImage --- .../java/fr/igred/ij/io/OMEROBatchImage.java | 949 ------------------ 1 file changed, 949 deletions(-) diff --git a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java index e4af77d..b35ba1c 100644 --- a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java +++ b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java @@ -43,37 +43,7 @@ public class OMEROBatchImage implements BatchImage { private final Client client; - private final Map tables = new HashMap<>(5); - - private boolean inputOnOMERO; - private boolean saveImage; - private boolean saveROIs; - private boolean saveResults; - private boolean saveLog; - private boolean loadROIs; - private boolean clearROIs; - private boolean outputOnOMERO; - private boolean outputOnLocal; - private boolean recursive; - private long inputDatasetId; - private long outputDatasetId; - private long outputProjectId; - private String directoryIn; - private String directoryOut; - private String suffix; - - private RoiManager rm; - - private BatchListener listener; - - public OMEROBatchImage(ScriptRunner script, Client client) { - this(script, client, new ProgressLog(LOGGER)); - } - - - public OMEROBatchImage(ScriptRunner script, Client client, ProgressMonitor progress) { - this.script = script; this.client = client; this.progress = progress; this.directoryIn = ""; @@ -84,484 +54,6 @@ public OMEROBatchImage(ScriptRunner script, Client client, ProgressMonitor progr } - /** - * Generates the timestamp for current time. - * - * @return See above. - */ - private static String timestamp() { - return DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss").format(ZonedDateTime.now()); - } - - - /** - * Removes file extension from image title. - * - * @param title Image title. - * - * @return The title, without the extension. - */ - private static String removeExtension(String title) { - if (title != null) { - int index = title.lastIndexOf('.'); - if (index == 0 || index == -1) { - return title; - } else { - String afterExt = TITLE_AFTER_EXT.matcher(title.substring(index + 1)).replaceAll("$1"); - String beforeExt = title.substring(0, index); - if (beforeExt.toLowerCase().endsWith(".ome") && beforeExt.lastIndexOf('.') > 0) { - beforeExt = beforeExt.substring(0, beforeExt.lastIndexOf('.')); - } - return afterExt.isEmpty() ? beforeExt : beforeExt + "_" + afterExt; - } - } else { - return null; - } - } - - - /** - * Deletes the temp folder. - * - * @param tmpDir The temp folder. - * - * @return True if the deletion was successful. - */ - private static boolean deleteTemp(String tmpDir) { - boolean deleted = true; - File dir = new File(tmpDir); - File[] entries = dir.listFiles(); - if (entries != null) { - try { - for (File entry : entries) { - deleted &= Files.deleteIfExists(entry.toPath()); - } - deleted &= Files.deleteIfExists(dir.toPath()); - } catch (IOException e) { - IJ.error("Could not delete files: " + e.getMessage()); - } - } - return deleted; - } - - - /** - * List all files contained in a directory - * - * @param directory The folder to process - * - * @return The list of images paths. - */ - private static List getFilesFromDirectory(String directory, boolean recursive) { - File dir = new File(directory); - File[] files = dir.listFiles(); - if (files == null) files = EMPTY_FILE_ARRAY; - List paths = new ArrayList<>(files.length); - for (File file : files) { - String path = file.getAbsolutePath(); - if (!file.isDirectory()) { - paths.add(path); - } else if (recursive) { - paths.addAll(getFilesFromDirectory(path, true)); - } - } - return paths; - } - - - /** - * Retrieves the images in a list of files using Bio-Formats. - * - * @param files The list of files. - * @param options The Bio-Formats importer options. - * - * @return A map containing the number of images for each file. - */ - private static Map getImagesFromFiles(Collection files, ImporterOptions options) { - List used = new ArrayList<>(files.size()); - Map imageFiles = new LinkedHashMap<>(files.size()); - for (String file : files) { - if (!used.contains(file)) { - // Open the image - options.setId(file); - ImportProcess process = new ImportProcess(options); - try { - process.execute(); - int n = process.getSeriesCount(); - FileStitcher fs = process.getFileStitcher(); - if (fs != null) used = Arrays.asList(fs.getUsedFiles()); - else used.add(file); - imageFiles.put(file, n); - } catch (IOException | FormatException e) { - LOGGER.info(e.getMessage()); - } - } - } - return imageFiles; - } - - - /** - * Retrieves the list of images open after the script was run. - * - * @param inputImage The input image. - * - * @return See above. - */ - private static List getOutputImages(ImagePlus inputImage) { - ImagePlus outputImage = WindowManager.getCurrentImage(); - if (outputImage == null) { - outputImage = inputImage; - } - int ijOutputId = outputImage.getID(); - - int[] imageIds = WindowManager.getIDList(); - if (imageIds == null) { - imageIds = EMPTY_INT_ARRAY; - } - List idList = Arrays.stream(imageIds).boxed().collect(Collectors.toList()); - idList.removeIf(i -> i.equals(ijOutputId)); - idList.add(0, ijOutputId); - return idList.stream() - .map(WindowManager::getImage) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } - - - /** - * Retrieves the list of ROIs from an image overlay. - * - * @param imp The image ROIs are linked to. - * - * @return See above. - */ - private static List getOverlay(ImagePlus imp) { - Overlay overlay = imp.getOverlay(); - List ijRois = new ArrayList<>(0); - if (overlay != null) { - ijRois = new ArrayList<>(Arrays.asList(overlay.toArray())); - } - for (Roi roi : ijRois) roi.setImage(imp); - return ijRois; - } - - - /** - * Converts ROIs from an image overlay to OMERO ROIs. - * - * @param imp The image ROIs are linked to. - * @param property The ROI property used to group shapes in OMERO. - * - * @return A list of OMERO ROIs. - */ - private static List getROIsFromOverlay(ImagePlus imp, String property) { - List rois = new ArrayList<>(0); - if (imp != null) { - List ijRois = getOverlay(imp); - rois = ROIWrapper.fromImageJ(ijRois, property); - } - - return rois; - } - - - /** - * Saves ImageJ ROIs to a file. - * - * @param ijRois The ROIs. - * @param path The path to the file. - */ - private static void saveRoiFile(List ijRois, String path) { - try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(path))); - DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(zos))) { - RoiEncoder re = new RoiEncoder(dos); - for (int i = 0; i < ijRois.size(); i++) { - if (ijRois.get(i) != null) { - // WARNING: Prepending index does not ensure label is unique. - String label = i + "-" + ijRois.get(i).getName() + ".roi"; - zos.putNextEntry(new ZipEntry(label)); - re.write(ijRois.get(i)); - dos.flush(); - } - } - } catch (IOException e) { - IJ.error("Error while saving ROI file: " + e.getMessage()); - } - } - - - /** - * Initializes the ROI manager. - */ - private void initRoiManager() { - rm = RoiManager.getInstance2(); - if (rm == null) rm = RoiManager.getRoiManager(); - rm.setVisible(false); - } - - - /** - * Initializes the Bio-Formats importer options. - * - * @return See above. - * - * @throws IOException If the importer options could not be initialized. - */ - private ImporterOptions initImporterOptions() throws IOException { - ImporterOptions options = new ImporterOptions(); - options.setStackFormat(ImporterOptions.VIEW_HYPERSTACK); - options.setSwapDimensions(false); - options.setOpenAllSeries(false); - options.setSpecifyRanges(false); - options.setShowMetadata(false); - options.setShowOMEXML(false); - options.setShowROIs(loadROIs); - options.setCrop(false); - options.setSplitChannels(false); - options.setSplitFocalPlanes(false); - options.setSplitTimepoints(false); - return options; - } - - - /** - * Sets the current state. - * - * @param text The text for the current state. - */ - private void setState(String text) { - if (progress != null) progress.setState(text); - } - - - /** - * Sets the current progress. - * - * @param text The text for the current progress. - */ - private void setProgress(String text) { - if (progress != null) progress.setProgress(text); - } - - - /** - * Signals the process is done. - */ - private void setDone() { - if (progress != null) progress.setDone(); - } - - - /** - * If this thread was constructed using a separate - * {@code Runnable} run object, then that - * {@code Runnable} object's {@code run} method is called; - * otherwise, this method does nothing and returns. - *

- * Subclasses of {@code Thread} should override this method. - * - * @see #start() - * @see Thread#Thread(ThreadGroup, Runnable, String) - */ - @Override - public void run() { - boolean finished = false; - if (progress instanceof ProgressDialog) { - ((Component) progress).setVisible(true); - } - - try { - if (!outputOnLocal) { - setState("Temporary directory creation..."); - directoryOut = Files.createTempDirectory("Fiji_analysis").toString(); - } - - if (inputOnOMERO) { - setState("Retrieving images from OMERO..."); - DatasetWrapper dataset = client.getDataset(inputDatasetId); - List images = dataset.getImages(client); - setState("Macro running..."); - runMacro(images); - } else { - setState("Retrieving files from input folder..."); - List files = getFilesFromDirectory(directoryIn, recursive); - setState("Macro running..."); - runMacroOnLocalImages(files); - } - setProgress(""); - uploadTables(); - - if (!outputOnLocal) { - setState("Temporary directory deletion..."); - if (!deleteTemp(directoryOut)) { - LOGGER.warning("Temp directory may not be deleted."); - } - } - finished = true; - setState(""); - setDone(); - } catch (NoSuchElementException | IOException | ServiceException | AccessException | ExecutionException e) { - finished = true; - setDone(); - setProgress("Macro cancelled"); - if (e.getMessage() != null && "Macro cancelled".equals(e.getMessage())) { - IJ.run("Close"); - } - IJ.error(e.getMessage()); - } finally { - if (!finished) { - setDone(); - setProgress("An unexpected error occurred."); - } - if (listener != null) listener.onThreadFinished(); - rm.setVisible(true); - rm.close(); - } - } - - - /** - * Deletes all owned ROIs from an image on OMERO. - * - * @param image The image on OMERO. - */ - private void deleteROIs(ImageWrapper image) { - setState("ROIs deletion from OMERO"); - try { - List rois = image.getROIs(client); - for (ROIWrapper roi : rois) { - if (roi.getOwner().getId() == client.getId()) { - client.delete(roi); - } - } - } catch (ExecutionException | OMEROServerError | ServiceException | AccessException exception) { - LOGGER.warning(exception.getMessage()); - } catch (InterruptedException e) { - LOGGER.warning(e.getMessage()); - Thread.currentThread().interrupt(); - } - } - - - /** - * Retrieves the list of ROIs from the ROI manager. - * - * @param imp The image ROIs are linked to. - * - * @return See above. - */ - private List getManagedRois(ImagePlus imp) { - List ijRois = new ArrayList<>(Arrays.asList(rm.getRoisAsArray())); - for (Roi roi : ijRois) roi.setImage(imp); - return ijRois; - } - - - /** - * Converts ROIs from the ROI Manager to OMERO ROIs. - * - * @param imp The image ROIs are linked to. - * @param property The ROI property used to group shapes in OMERO. - * - * @return A list of OMERO ROIs. - */ - private List getROIsFromManager(ImagePlus imp, String property) { - List rois = new ArrayList<>(0); - if (imp != null) { - List ijRois = getManagedRois(imp); - rois = ROIWrapper.fromImageJ(ijRois, property); - } - - return rois; - } - - - /** - * Runs a macro on images from OMERO and saves the results. - * - * @param images List of images on OMERO. - */ - void runMacro(List images) { - String property = ROIWrapper.IJ_PROPERTY; - WindowManager.closeAllWindows(); - int index = 0; - for (ImageWrapper image : images) { - setProgress("Image " + (index + 1) + "/" + images.size()); - long inputImageId = image.getId(); - - // Open image from OMERO - ImagePlus imp = openImage(image); - // If image could not be loaded, continue to next image. - if (imp != null) { - // Initialize ROI Manager - initRoiManager(); - - // Load ROIs - if (loadROIs) loadROIs(image, imp, false); - - imp.show(); - - // Analyse the image - script.setImage(imp); - script.run(); - - imp.changes = false; // Prevent "Save Changes?" dialog - save(imp, inputImageId, property); - } - closeWindows(); - index++; - } - } - - - /** - * Runs a macro on local files and saves the results. - * - * @param files List of image files. - * - * @throws IOException A problem occurred reading a file. - */ - void runMacroOnLocalImages(Collection files) throws IOException { - String property = ROIWrapper.IJ_PROPERTY; - WindowManager.closeAllWindows(); - - ImporterOptions options = initImporterOptions(); - Map imageFiles = getImagesFromFiles(files, options); - int nFile = 1; - for (Map.Entry entry : imageFiles.entrySet()) { - int n = entry.getValue(); - options.setId(entry.getKey()); - for (int i = 0; i < n; i++) { - String msg = String.format("File %d/%d, image %d/%d", nFile, imageFiles.size(), i + 1, n); - setProgress(msg); - options.setSeriesOn(i, true); - try { - ImagePlus[] imps = BF.openImagePlus(options); - ImagePlus imp = imps[0]; - imp.show(); - - // Initialize ROI Manager - initRoiManager(); - - // Analyse the image - script.setImage(imp); - script.run(); - - // Save and Close the various components - imp.changes = false; // Prevent "Save Changes?" dialog - save(imp, null, property); - } catch (FormatException e) { - IJ.error(e.getMessage()); - } - closeWindows(); - options.setSeriesOn(i, false); - } - nFile++; - } - } - - /** * Opens an image from OMERO. * @@ -617,445 +109,4 @@ private void loadROIs(ImageWrapper image, ImagePlus imp, boolean toOverlay) { } } - - /** - * Saves the images, results and ROIs. - * - * @param inputImage The input image in ImageJ. - * @param omeroInputId The OMERO image input ID. - * @param property The ROI property used to group shapes in OMERO. - */ - private void save(ImagePlus inputImage, Long omeroInputId, String property) { - String inputTitle = removeExtension(inputImage.getTitle()); - - Long omeroOutputId = omeroInputId; - List outputs = getOutputImages(inputImage); - - ImagePlus outputImage = inputImage; - if (!outputs.isEmpty()) outputImage = outputs.get(0); - - // If input image is expected as output for ROIs on OMERO but is not annotable, import it. - boolean annotable = Boolean.parseBoolean(inputImage.getProp("Annotable")); - boolean outputIsNotInput = !inputImage.equals(outputImage); - if (!outputOnOMERO || !saveROIs || annotable || outputIsNotInput) { - outputs.removeIf(inputImage::equals); - } - - if (saveImage) { - if (outputs.isEmpty()) LOGGER.info("Warning: there is no new image."); - List outputIds = new ArrayList<>(outputs.size()); - outputs.forEach(imp -> outputIds.addAll(saveImage(imp, property))); - if (!outputIds.isEmpty() && outputIsNotInput) { - omeroOutputId = outputIds.get(0); - } - } - - if (saveROIs) { - if (!saveImage) saveOverlay(outputImage, omeroOutputId, inputTitle, property); - saveROIManager(outputImage, omeroOutputId, inputTitle, property); - } - if (saveResults) saveResults(outputImage, omeroOutputId, inputTitle, property); - if (saveLog) saveLog(omeroOutputId, inputTitle); - - for (ImagePlus imp : outputs) { - imp.changes = false; - imp.close(); - } - } - - - /** - * Saves an image. - * - * @param image The image to save. - * @param property The ROI property to group shapes in OMERO. - * - * @return The OMERO IDs of the (possibly) uploaded image. Should be empty or contain one value. - */ - private List saveImage(ImagePlus image, String property) { - List ids = new ArrayList<>(0); - String title = removeExtension(image.getTitle()); - String path = directoryOut + File.separator + title + suffix + ".tif"; - IJ.saveAsTiff(image, path); - if (outputOnOMERO) { - try { - setState("Import on OMERO..."); - DatasetWrapper dataset = client.getDataset(outputDatasetId); - ids = dataset.importImage(client, path); - if (saveROIs && !ids.isEmpty()) { - saveOverlay(image, ids.get(0), title, property); - } - } catch (AccessException | ServiceException | OMEROServerError | ExecutionException e) { - IJ.error("Could not import image: " + e.getMessage()); - } - } - return ids; - } - - - /** - * Saves the ROIs from an image overlay in ImageJ. - * - * @param imp The image. - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. - * @param property The ROI property used to group shapes on OMERO. - */ - private void saveOverlay(ImagePlus imp, Long imageId, String title, String property) { - if (outputOnLocal) { // local save - setState("Saving overlay ROIs..."); - String path = directoryOut + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; - List ijRois = getOverlay(imp); - saveRoiFile(ijRois, path); - } - if (outputOnOMERO && imageId != null) { // save on Omero - List rois = getROIsFromOverlay(imp, property); - try { - ImageWrapper image = client.getImage(imageId); - if (clearROIs) { - deleteROIs(image); - } - setState("Saving overlay ROIs on OMERO..."); - image.saveROIs(client, rois); - loadROIs(image, imp, true); // reload ROIs - } catch (ServiceException | AccessException | ExecutionException e) { - IJ.error("Could not import overlay ROIs to OMERO: " + e.getMessage()); - } - } - } - - - /** - * Saves the ROIs from the ROI Manager (for an image). - * - * @param imp The image. - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. - * @param property The ROI property used to group shapes on OMERO. - */ - private void saveROIManager(ImagePlus imp, Long imageId, String title, String property) { - if (outputOnLocal) { // local save - setState("Saving ROIs..."); - String path = directoryOut + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; - List ijRois = getManagedRois(imp); - saveRoiFile(ijRois, path); - } - if (outputOnOMERO && imageId != null) { // save on Omero - List rois = getROIsFromManager(imp, property); - try { - ImageWrapper image = client.getImage(imageId); - if (clearROIs) { - deleteROIs(image); - } - setState("Saving ROIs on OMERO..."); - image.saveROIs(client, rois); - loadROIs(image, imp, false); // reload ROIs - } catch (ServiceException | AccessException | ExecutionException e) { - IJ.error("Could not import ROIs to OMERO: " + e.getMessage()); - } - } - } - - - /** - * Saves the results (linked to an image). - * - * @param imp The image. - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. - * @param property The ROI property used to group shapes on OMERO. - */ - private void saveResults(ImagePlus imp, Long imageId, String title, String property) { - List ijRois = getOverlay(imp); - ijRois.addAll(getManagedRois(imp)); - - setState("Saving results files..."); - String[] candidates = WindowManager.getNonImageTitles(); - List results = Arrays.stream(candidates) - .map(ResultsTable::getResultsTable) - .collect(Collectors.toList()); - results.add(0, ResultsTable.getResultsTable()); - Map processed = new HashMap<>(results.size()); - for (ResultsTable rt : results) { - if (rt != null) { - String name = rt.getTitle(); - if (!Boolean.TRUE.equals(processed.get(name)) && rt.getHeadings().length > 0) { - String path = directoryOut + File.separator + name + "_" + title + "_" + timestamp() + ".csv"; - rt.save(path); - if (outputOnOMERO) { - appendTable(rt, imageId, ijRois, property); - uploadFile(imageId, path); - } - rt.reset(); - processed.put(name, true); - } - } - } - } - - - /** - * Saves the log. - * - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. - */ - private void saveLog(Long imageId, String title) { - String path = directoryOut + File.separator + title + "_log.txt"; - IJ.selectWindow("Log"); - IJ.saveAs("txt", path); - if (outputOnOMERO) uploadFile(imageId, path); - } - - - /** - * Uploads a file to an image on OMERO. - * - * @param imageId The image ID on OMERO. - * @param path The path to the file. - */ - private void uploadFile(Long imageId, String path) { - if (imageId != null) { - try { - setState("Uploading results files..."); - ImageWrapper image = client.getImage(imageId); - image.addFile(client, new File(path)); - } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Error adding file to image:" + e.getMessage()); - } catch (InterruptedException e) { - IJ.error("Error adding file to image:" + e.getMessage()); - Thread.currentThread().interrupt(); - } - } - } - - - /** - * Adds the current results to the corresponding table. - * - * @param results The results table. - * @param imageId The image ID on OMERO. - * @param ijRois The ROIs in ImageJ. - * @param property The ROI property used to group shapes on OMERO. - */ - private void appendTable(ResultsTable results, Long imageId, List ijRois, String property) { - String resultsName = results.getTitle(); - TableWrapper table = tables.get(resultsName); - try { - if (table == null) { - tables.put(resultsName, new TableWrapper(client, results, imageId, ijRois, property)); - } else { - table.addRows(client, results, imageId, ijRois, property); - } - } catch (ServiceException | AccessException | ExecutionException e) { - IJ.error("Could not create or append table: " + e.getMessage()); - } - } - - - /** - * Upload the tables to OMERO. - */ - private void uploadTables() { - if (outputOnOMERO && saveResults) { - setState("Uploading tables..."); - try { - ProjectWrapper project = client.getProject(outputProjectId); - for (Map.Entry entry : tables.entrySet()) { - String name = entry.getKey(); - TableWrapper table = entry.getValue(); - String newName; - if (name == null || name.isEmpty()) newName = timestamp() + "_" + table.getName(); - else newName = timestamp() + "_" + name; - table.setName(newName); - project.addTable(client, table); - String path = directoryOut + File.separator + newName + ".csv"; - table.saveAs(path, 'c'); - project.addFile(client, new File(path)); - } - } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Could not save table: " + e.getMessage()); - } catch (IOException e) { - IJ.error("Could not save table as file: " + e.getMessage()); - } catch (InterruptedException e) { - IJ.error("Could not upload CSV to project: " + e.getMessage()); - Thread.currentThread().interrupt(); - } - } - } - - - /** - * Closes all open windows in ImageJ. - */ - private void closeWindows() { - for (Frame frame : WindowManager.getNonImageWindows()) { - if (frame instanceof TextWindow) { - ((TextWindow) frame).close(false); - } - } - rm.reset(); - WindowManager.closeAllWindows(); - } - - - public Client getClient() { - return client; - } - - - public long getOutputProjectId() { - return outputProjectId; - } - - - public void setOutputProjectId(Long outputProjectId) { - if (outputProjectId != null) this.outputProjectId = outputProjectId; - } - - - public long getOutputDatasetId() { - return outputDatasetId; - } - - - public void setOutputDatasetId(Long outputDatasetId) { - if (outputDatasetId != null) this.outputDatasetId = outputDatasetId; - } - - - public long getInputDatasetId() { - return inputDatasetId; - } - - - public void setInputDatasetId(Long inputDatasetId) { - if (inputDatasetId != null) this.inputDatasetId = inputDatasetId; - } - - - public boolean shouldSaveROIs() { - return saveROIs; - } - - - public void setSaveROIs(boolean saveROIs) { - this.saveROIs = saveROIs; - } - - - public boolean shouldSaveResults() { - return saveResults; - } - - - public void setSaveResults(boolean saveResults) { - this.saveResults = saveResults; - } - - - public boolean isInputOnOMERO() { - return inputOnOMERO; - } - - - public void setInputOnOMERO(boolean inputOnOMERO) { - this.inputOnOMERO = inputOnOMERO; - } - - - public boolean shouldSaveImage() { - return saveImage; - } - - - public void setSaveImage(boolean saveImage) { - this.saveImage = saveImage; - } - - - public boolean shouldLoadROIs() { - return loadROIs; - } - - - public void setLoadROIS(boolean loadROIs) { - this.loadROIs = loadROIs; - } - - - public boolean shouldClearROIs() { - return clearROIs; - } - - - public void setClearROIS(boolean clearROIs) { - this.clearROIs = clearROIs; - } - - - public String getDirectoryIn() { - return directoryIn; - } - - - public void setDirectoryIn(String directoryIn) { - this.directoryIn = directoryIn; - } - - - public String getDirectoryOut() { - return directoryOut; - } - - - public void setDirectoryOut(String directoryOut) { - this.directoryOut = directoryOut; - } - - - public String getSuffix() { - return suffix; - } - - - public void setSuffix(String suffix) { - this.suffix = suffix; - } - - - public boolean isOutputOnOMERO() { - return outputOnOMERO; - } - - - public void setOutputOnOMERO(boolean outputOnOMERO) { - this.outputOnOMERO = outputOnOMERO; - } - - - public boolean isOutputOnLocal() { - return outputOnLocal; - } - - - public void setOutputOnLocal(boolean outputOnLocal) { - this.outputOnLocal = outputOnLocal; - } - - - public void setSaveLog(boolean saveLog) { - this.saveLog = saveLog; - } - - - public void setListener(BatchListener listener) { - this.listener = listener; - } - - - public void setRecursive(boolean recursive) { - this.recursive = recursive; - } - } From ee85e32cae4dbc78366a2a5987da768ab9da3cbe Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 13:54:22 +0100 Subject: [PATCH 11/33] Rename openImage method --- .../java/fr/igred/ij/io/OMEROBatchImage.java | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java index b35ba1c..6c4d1fb 100644 --- a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java +++ b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java @@ -42,34 +42,29 @@ public class OMEROBatchImage implements BatchImage { private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName()); private final Client client; + private final ImageWrapper imageWrapper; - public OMEROBatchImage(ScriptRunner script, Client client) { + + public OMEROBatchImage(Client client, ImageWrapper imageWrapper) { this.client = client; - this.progress = progress; - this.directoryIn = ""; - this.suffix = ""; - this.directoryOut = null; - this.rm = null; - this.listener = null; + this.imageWrapper = imageWrapper; } /** - * Opens an image from OMERO. - * - * @param image An OMERO image. + * Opens the image and returns the corresponding ImagePlus. * - * @return An ImagePlus. + * @return See above. */ - private ImagePlus openImage(ImageWrapper image) { - setState("Opening image from OMERO..."); + @Override + public ImagePlus getImagePlus(ROIMode mode) { ImagePlus imp = null; try { - imp = image.toImagePlus(client); + imp = imageWrapper.toImagePlus(client); // Store image "annotate" permissions as a property in the ImagePlus object - imp.setProp("Annotatable", String.valueOf(image.canAnnotate())); + imp.setProp("Annotatable", String.valueOf(imageWrapper.canAnnotate())); } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Could not load image: " + e.getMessage()); + LOGGER.severe("Could not load image: " + e.getMessage()); } return imp; } @@ -87,7 +82,7 @@ private void loadROIs(ImageWrapper image, ImagePlus imp, boolean toOverlay) { try { ijRois = ROIWrapper.toImageJ(image.getROIs(client)); } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Could not load ROIs: " + e.getMessage()); + LOGGER.severe("Could not load ROIs: " + e.getMessage()); } if (toOverlay) { Overlay overlay = imp.getOverlay(); From 7aa3477f3aad52df29e4f53e6b235eec2a556efe Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 14:00:32 +0100 Subject: [PATCH 12/33] Add appropriate methods to OMEROBatchImage --- .../java/fr/igred/ij/io/OMEROBatchImage.java | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java index 6c4d1fb..be4a789 100644 --- a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java +++ b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java @@ -51,6 +51,30 @@ public OMEROBatchImage(Client client, ImageWrapper imageWrapper) { } + /** + * Creates a list of OMERO images to be opened. + * + * @param client The OMERO client. + * @param images The list of ImageWrappers. + * + * @return The list of images. + */ + public static List listImages(Client client, Collection images) { + return images.stream().map(i -> new OMEROBatchImage(client, i)).collect(Collectors.toList()); + } + + + /** + * Returns the related ImageWrapper, or null if there is none. + * + * @return See above. + */ + @Override + public ImageWrapper getImageWrapper() { + return imageWrapper; + } + + /** * Opens the image and returns the corresponding ImagePlus. * @@ -63,6 +87,7 @@ public ImagePlus getImagePlus(ROIMode mode) { imp = imageWrapper.toImagePlus(client); // Store image "annotate" permissions as a property in the ImagePlus object imp.setProp("Annotatable", String.valueOf(imageWrapper.canAnnotate())); + loadROIs(imp, mode); } catch (ExecutionException | ServiceException | AccessException e) { LOGGER.severe("Could not load image: " + e.getMessage()); } @@ -73,18 +98,21 @@ public ImagePlus getImagePlus(ROIMode mode) { /** * Loads ROIs from an image in OMERO into ImageJ. * - * @param image The OMERO image. - * @param imp The image in ImageJ ROIs should be linked to. - * @param toOverlay Whether the ROIs should be loaded to the ROI Manager (false) or the overlay (true). + * @param imp The image in ImageJ ROIs should be linked to. + * @param roiMode The mode used to load ROIs. */ - private void loadROIs(ImageWrapper image, ImagePlus imp, boolean toOverlay) { + private void loadROIs(ImagePlus imp, ROIMode roiMode) { List ijRois = new ArrayList<>(0); + RoiManager rm = RoiManager.getInstance2(); + if (rm == null) { + rm = RoiManager.getRoiManager(); + } try { - ijRois = ROIWrapper.toImageJ(image.getROIs(client)); + ijRois = ROIWrapper.toImageJ(imageWrapper.getROIs(client)); } catch (ExecutionException | ServiceException | AccessException e) { LOGGER.severe("Could not load ROIs: " + e.getMessage()); } - if (toOverlay) { + if (roiMode == ROIMode.OVERLAY) { Overlay overlay = imp.getOverlay(); if (overlay != null) { overlay.clear(); @@ -95,7 +123,7 @@ private void loadROIs(ImageWrapper image, ImagePlus imp, boolean toOverlay) { ijRoi.setImage(imp); overlay.add(ijRoi, ijRoi.getName()); } - } else { + } else if (rm != null) { rm.reset(); // Reset ROI manager to clear previous ROIs for (Roi ijRoi : ijRois) { ijRoi.setImage(imp); From bafd3b0574498f47d154335493cd597d1cc91652 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 14:35:42 +0100 Subject: [PATCH 13/33] Adapt OMEROBatchPlugin --- README.md | 4 +- .../fr/igred/ij/gui/OMEROConnectDialog.java | 2 +- .../java/fr/igred/ij/io/OMEROBatchImage.java | 4 +- .../fr/igred/ij/macro/OMEROBatchRunner.java | 5 +- .../ij/plugin/frame/OMEROBatchPlugin.java | 58 +++++++++++-------- 5 files changed, 42 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index ef0685a..1662102 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ An ImageJ plugin to run a script on a batch of images from/to OMERO. 1. Install the [OMERO.insight plugin](https://omero-guides.readthedocs.io/en/latest/fiji/docs/installation.html) (if you haven't already). -2. Download the JAR file for this [library](https://github.com/GReD-Clermont/simple-omero-client/releases/tag/5.12.1/). -3. Download the JAR file ([for this plugin](https://github.com/GReD-Clermont/omero_batch-plugin/releases/tag/1.0.5/)). +2. Download the JAR file for this [library](https://github.com/GReD-Clermont/simple-omero-client/releases/tag/5.16.0/). +3. Download the JAR file ([for this plugin](https://github.com/GReD-Clermont/omero_batch-plugin/releases/tag/2.0.0/)). 4. Place these JAR files in your "plugins" folder. ## How to use diff --git a/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java b/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java index 8284683..5729c6a 100644 --- a/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java +++ b/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 diff --git a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java index be4a789..803c216 100644 --- a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java +++ b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java @@ -87,7 +87,9 @@ public ImagePlus getImagePlus(ROIMode mode) { imp = imageWrapper.toImagePlus(client); // Store image "annotate" permissions as a property in the ImagePlus object imp.setProp("Annotatable", String.valueOf(imageWrapper.canAnnotate())); - loadROIs(imp, mode); + if (imp != null) { + loadROIs(imp, mode); + } } catch (ExecutionException | ServiceException | AccessException e) { LOGGER.severe("Could not load image: " + e.getMessage()); } diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index ab660c1..73090b2 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 @@ -97,6 +97,7 @@ public class OMEROBatchRunner extends Thread { private BatchListener listener; + public OMEROBatchRunner(ScriptRunner script, List images, Client client) { this(script, images, client, new ProgressLog(LOGGER)); } @@ -139,7 +140,7 @@ private static String removeExtension(String title) { } else { String afterExt = TITLE_AFTER_EXT.matcher(title.substring(index + 1)).replaceAll("$1"); String beforeExt = title.substring(0, index); - if(beforeExt.toLowerCase().endsWith(".ome") && beforeExt.lastIndexOf('.') > 0) { + if (beforeExt.toLowerCase().endsWith(".ome") && beforeExt.lastIndexOf('.') > 0) { beforeExt = beforeExt.substring(0, beforeExt.lastIndexOf('.')); } return afterExt.isEmpty() ? beforeExt : beforeExt + "_" + afterExt; diff --git a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java index e6f8792..90c0ef0 100644 --- a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java +++ b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 @@ -18,6 +18,7 @@ import fr.igred.ij.gui.OMEROConnectDialog; import fr.igred.ij.gui.ProgressDialog; +import fr.igred.ij.io.BatchImage; import fr.igred.ij.macro.BatchListener; import fr.igred.ij.macro.OMEROBatchRunner; import fr.igred.ij.macro.ScriptRunner; @@ -58,6 +59,8 @@ import java.util.logging.Logger; import java.util.stream.Collectors; +import static fr.igred.ij.io.LocalBatchImage.listImages; +import static fr.igred.ij.io.OMEROBatchImage.listImages; import static javax.swing.JOptionPane.showMessageDialog; /** @@ -920,43 +923,48 @@ private void previewDataset() { */ public void start(ActionEvent e) { ProgressDialog progress = new ProgressDialog(); - OMEROBatchRunner runner = new OMEROBatchRunner(script, client, progress); - runner.setListener(this); + OMEROBatchRunner runner; - // initiation of success variables + // initialization of success variables boolean checkInput; boolean checkMacro = getMacro(); boolean checkOutput = getOutput(); // input data - if (omero.isSelected()) { - runner.setInputOnOMERO(true); - int index = datasetListIn.getSelectedIndex(); - DatasetWrapper dataset = datasets.get(index); - long inputDatasetId = dataset.getId(); - runner.setInputDatasetId(inputDatasetId); + List images; + long inputDatasetId = -1L; + try { + if (omero.isSelected()) { + int index = datasetListIn.getSelectedIndex(); + DatasetWrapper dataset = datasets.get(index); + inputDatasetId = dataset.getId(); + List imageWrappers = dataset.getImages(client); + images = listImages(client, imageWrappers); + checkInput = true; + } else { // local.isSelected() + checkInput = getLocalInput(); + images = listImages(directoryIn, recursive.isSelected()); + } + runner = new OMEROBatchRunner(script, images, client, progress); runner.setOutputDatasetId(inputDatasetId); - checkInput = true; - } else { // local.isSelected() - runner.setInputOnOMERO(false); - checkInput = getLocalInput(); - runner.setDirectoryIn(directoryIn); - runner.setRecursive(recursive.isSelected()); + runner.setListener(this); + + runner.setSuffix(suffix.getText()); + runner.setLoadROIS(checkLoadROIs.isSelected()); + runner.setClearROIS(checkDelROIs.isSelected()); + runner.setSaveImage(checkImage.isSelected()); + runner.setSaveResults(checkResults.isSelected()); + runner.setSaveROIs(checkROIs.isSelected()); + runner.setSaveLog(checkLog.isSelected()); + } catch (ServiceException | AccessException | ExecutionException | IOException exception) { + IJ.error(exception.getMessage()); + return; } if (!checkInput || !checkMacro || !checkOutput) { return; } - // suffix - runner.setSuffix(suffix.getText()); - - runner.setLoadROIS(checkLoadROIs.isSelected()); - runner.setClearROIS(checkDelROIs.isSelected()); - runner.setSaveImage(checkImage.isSelected()); - runner.setSaveResults(checkResults.isSelected()); - runner.setSaveROIs(checkROIs.isSelected()); - runner.setSaveLog(checkLog.isSelected()); if (onlineOutput.isSelected()) { runner.setOutputOnOMERO(true); if (checkResults.isSelected()) { From b66c62ebbf15ca4495231f217cd6df5fb2b2c49b Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 20:34:09 +0100 Subject: [PATCH 14/33] Rename OMEROBatchRunner.java to BatchParameters.java --- .../ij/macro/{OMEROBatchRunner.java => BatchParameters.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/fr/igred/ij/macro/{OMEROBatchRunner.java => BatchParameters.java} (100%) diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/BatchParameters.java similarity index 100% rename from src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java rename to src/main/java/fr/igred/ij/macro/BatchParameters.java From 4c1d09ac0846576617576c1bd8575e7397689b1d Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 20:35:29 +0100 Subject: [PATCH 15/33] Rename OMEROBatchRunner to BatchParameters --- src/main/java/fr/igred/ij/macro/BatchParameters.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/igred/ij/macro/BatchParameters.java b/src/main/java/fr/igred/ij/macro/BatchParameters.java index 73090b2..4c58e61 100644 --- a/src/main/java/fr/igred/ij/macro/BatchParameters.java +++ b/src/main/java/fr/igred/ij/macro/BatchParameters.java @@ -63,9 +63,9 @@ import java.util.zip.ZipOutputStream; /** - * Runs a script over multiple images retrieved from local files or from OMERO. + * Holds the parameters to batch run scripts. */ -public class OMEROBatchRunner extends Thread { +public class BatchParameters { private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName()); @@ -98,12 +98,12 @@ public class OMEROBatchRunner extends Thread { private BatchListener listener; - public OMEROBatchRunner(ScriptRunner script, List images, Client client) { + public BatchParameters(ScriptRunner script, List images, Client client) { this(script, images, client, new ProgressLog(LOGGER)); } - public OMEROBatchRunner(ScriptRunner script, List images, Client client, ProgressMonitor progress) { + public BatchParameters(ScriptRunner script, List images, Client client, ProgressMonitor progress) { this.script = script; this.images = new ArrayList<>(images); this.client = client; From 3a7512983473feb0865e91c4c795ca03868a8417 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 20:48:32 +0100 Subject: [PATCH 16/33] Only keep relevant methods in BatchParameters --- .../fr/igred/ij/macro/BatchParameters.java | 827 +++--------------- 1 file changed, 119 insertions(+), 708 deletions(-) diff --git a/src/main/java/fr/igred/ij/macro/BatchParameters.java b/src/main/java/fr/igred/ij/macro/BatchParameters.java index 4c58e61..3838ab3 100644 --- a/src/main/java/fr/igred/ij/macro/BatchParameters.java +++ b/src/main/java/fr/igred/ij/macro/BatchParameters.java @@ -16,70 +16,11 @@ */ package fr.igred.ij.macro; -import fr.igred.ij.gui.ProgressDialog; -import fr.igred.ij.io.BatchImage; -import fr.igred.ij.io.ROIMode; -import fr.igred.omero.Client; -import fr.igred.omero.annotations.TableWrapper; -import fr.igred.omero.exception.AccessException; -import fr.igred.omero.exception.OMEROServerError; -import fr.igred.omero.exception.ServiceException; -import fr.igred.omero.repository.DatasetWrapper; -import fr.igred.omero.repository.ImageWrapper; -import fr.igred.omero.repository.ProjectWrapper; -import fr.igred.omero.roi.ROIWrapper; -import ij.IJ; -import ij.ImagePlus; -import ij.WindowManager; -import ij.gui.Overlay; -import ij.gui.Roi; -import ij.io.RoiEncoder; -import ij.measure.ResultsTable; -import ij.plugin.frame.RoiManager; -import ij.text.TextWindow; - -import java.awt.Component; -import java.awt.Frame; -import java.io.BufferedOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.nio.file.Files; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ExecutionException; -import java.util.logging.Logger; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - /** * Holds the parameters to batch run scripts. */ public class BatchParameters { - private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName()); - - private static final int[] EMPTY_INT_ARRAY = new int[0]; - - private static final Pattern TITLE_AFTER_EXT = Pattern.compile("\\w+\\s?\\[?([^\\[\\]]*)]?"); - - private final List images; - private final ScriptRunner script; - private final Client client; - private final ProgressMonitor progress; - - private final Map tables = new HashMap<>(5); - private boolean loadROIs; private boolean saveImage; private boolean saveROIs; @@ -93,806 +34,276 @@ public class BatchParameters { private String directoryOut; private String suffix; - private RoiManager rm; - - private BatchListener listener; - - public BatchParameters(ScriptRunner script, List images, Client client) { - this(script, images, client, new ProgressLog(LOGGER)); - } - - - public BatchParameters(ScriptRunner script, List images, Client client, ProgressMonitor progress) { - this.script = script; - this.images = new ArrayList<>(images); - this.client = client; - this.progress = progress; + public BatchParameters() { + this.loadROIs = false; + this.saveImage = false; + this.saveROIs = false; + this.saveResults = false; + this.saveLog = false; + this.clearROIs = false; + this.outputOnOMERO = false; + this.outputOnLocal = false; + this.outputDatasetId = -1L; + this.outputProjectId = -1L; this.suffix = ""; this.directoryOut = null; - this.rm = null; - this.listener = null; } - /** - * Generates the timestamp for current time. - * - * @return See above. - */ - private static String timestamp() { - return DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss").format(ZonedDateTime.now()); + public BatchParameters(BatchParameters parameters) { + this.loadROIs = parameters.loadROIs; + this.saveImage = parameters.saveImage; + this.saveROIs = parameters.saveROIs; + this.saveResults = parameters.saveResults; + this.saveLog = parameters.saveLog; + this.clearROIs = parameters.clearROIs; + this.outputOnOMERO = parameters.outputOnOMERO; + this.outputOnLocal = parameters.outputOnLocal; + this.outputDatasetId = parameters.outputDatasetId; + this.outputProjectId = parameters.outputProjectId; + this.suffix = parameters.suffix; + this.directoryOut = parameters.directoryOut; } /** - * Removes file extension from image title. - * - * @param title Image title. + * Returns the output project ID. * - * @return The title, without the extension. + * @return See above. */ - private static String removeExtension(String title) { - if (title != null) { - int index = title.lastIndexOf('.'); - if (index == 0 || index == -1) { - return title; - } else { - String afterExt = TITLE_AFTER_EXT.matcher(title.substring(index + 1)).replaceAll("$1"); - String beforeExt = title.substring(0, index); - if (beforeExt.toLowerCase().endsWith(".ome") && beforeExt.lastIndexOf('.') > 0) { - beforeExt = beforeExt.substring(0, beforeExt.lastIndexOf('.')); - } - return afterExt.isEmpty() ? beforeExt : beforeExt + "_" + afterExt; - } - } else { - return null; - } + public long getOutputProjectId() { + return outputProjectId; } /** - * Deletes the temp folder. - * - * @param tmpDir The temp folder. + * Sets the output project ID. * - * @return True if the deletion was successful. + * @param outputProjectId See above. */ - private static boolean deleteTemp(String tmpDir) { - boolean deleted = true; - File dir = new File(tmpDir); - File[] entries = dir.listFiles(); - if (entries != null) { - try { - for (File entry : entries) { - deleted &= Files.deleteIfExists(entry.toPath()); - } - deleted &= Files.deleteIfExists(dir.toPath()); - } catch (IOException e) { - IJ.error("Could not delete files: " + e.getMessage()); - } - } - return deleted; + public void setOutputProjectId(Long outputProjectId) { + if (outputProjectId != null) this.outputProjectId = outputProjectId; } /** - * Retrieves the list of images open after the script was run. - * - * @param inputImage The input image. + * Returns the output dataset ID. * * @return See above. */ - private static List getOutputImages(ImagePlus inputImage) { - ImagePlus outputImage = WindowManager.getCurrentImage(); - if (outputImage == null) { - outputImage = inputImage; - } - int ijOutputId = outputImage.getID(); - - int[] imageIds = WindowManager.getIDList(); - if (imageIds == null) { - imageIds = EMPTY_INT_ARRAY; - } - List idList = Arrays.stream(imageIds).boxed().collect(Collectors.toList()); - idList.removeIf(i -> i.equals(ijOutputId)); - idList.add(0, ijOutputId); - return idList.stream() - .map(WindowManager::getImage) - .filter(Objects::nonNull) - .collect(Collectors.toList()); + public long getOutputDatasetId() { + return outputDatasetId; } /** - * Retrieves the list of ROIs from an image overlay. - * - * @param imp The image ROIs are linked to. + * Sets the output dataset ID. * - * @return See above. + * @param outputDatasetId See above. */ - private static List getOverlay(ImagePlus imp) { - Overlay overlay = imp.getOverlay(); - List ijRois = new ArrayList<>(0); - if (overlay != null) { - ijRois = new ArrayList<>(Arrays.asList(overlay.toArray())); - } - for (Roi roi : ijRois) roi.setImage(imp); - return ijRois; + public void setOutputDatasetId(Long outputDatasetId) { + if (outputDatasetId != null) this.outputDatasetId = outputDatasetId; } /** - * Converts ROIs from an image overlay to OMERO ROIs. + * Returns whether the ROIs should be saved or not. * - * @param imp The image ROIs are linked to. - * @param property The ROI property used to group shapes in OMERO. - * - * @return A list of OMERO ROIs. + * @return See above. */ - private static List getROIsFromOverlay(ImagePlus imp, String property) { - List rois = new ArrayList<>(0); - if (imp != null) { - List ijRois = getOverlay(imp); - rois = ROIWrapper.fromImageJ(ijRois, property); - } - - return rois; + public boolean shouldSaveROIs() { + return saveROIs; } /** - * Saves ImageJ ROIs to a file. + * Sets whether the ROIs should be saved or not. * - * @param ijRois The ROIs. - * @param path The path to the file. + * @param saveROIs See above. */ - private static void saveRoiFile(List ijRois, String path) { - try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(path))); - DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(zos))) { - RoiEncoder re = new RoiEncoder(dos); - for (int i = 0; i < ijRois.size(); i++) { - if (ijRois.get(i) != null) { - // WARNING: Prepending index does not ensure label is unique. - String label = i + "-" + ijRois.get(i).getName() + ".roi"; - zos.putNextEntry(new ZipEntry(label)); - re.write(ijRois.get(i)); - dos.flush(); - } - } - } catch (IOException e) { - IJ.error("Error while saving ROI file: " + e.getMessage()); - } - } - - - /** - * Initializes the ROI manager. - */ - private void initRoiManager() { - rm = RoiManager.getInstance2(); - if (rm == null) rm = RoiManager.getRoiManager(); - rm.setVisible(false); + public void setSaveROIs(boolean saveROIs) { + this.saveROIs = saveROIs; } /** - * Sets the current state. + * Returns whether the results tables should be saved or not. * - * @param text The text for the current state. + * @return See above. */ - private void setState(String text) { - if (progress != null) progress.setState(text); + public boolean shouldSaveResults() { + return saveResults; } /** - * Sets the current progress. + * Sets whether the results tables should be saved or not. * - * @param text The text for the current progress. + * @param saveResults See above. */ - private void setProgress(String text) { - if (progress != null) progress.setProgress(text); - } - - - /** - * Signals the process is done. - */ - private void setDone() { - if (progress != null) progress.setDone(); + public void setSaveResults(boolean saveResults) { + this.saveResults = saveResults; } /** - * If this thread was constructed using a separate - * {@code Runnable} run object, then that - * {@code Runnable} object's {@code run} method is called; - * otherwise, this method does nothing and returns. - *

- * Subclasses of {@code Thread} should override this method. + * Returns whether the images should be saved or not. * - * @see #start() - * @see Thread#Thread(ThreadGroup, Runnable, String) + * @return See above. */ - @Override - public void run() { - boolean finished = false; - if (progress instanceof ProgressDialog) { - ((Component) progress).setVisible(true); - } - - try { - if (!outputOnLocal) { - setState("Temporary directory creation..."); - directoryOut = Files.createTempDirectory("Fiji_analysis").toString(); - } - - setState("Macro running..."); - runMacro(); - setProgress(""); - uploadTables(); - - if (!outputOnLocal) { - setState("Temporary directory deletion..."); - if (!deleteTemp(directoryOut)) { - LOGGER.warning("Temp directory may not be deleted."); - } - } - finished = true; - setState(""); - setDone(); - } catch (IOException e) { - finished = true; - setDone(); - setProgress("Macro cancelled"); - if (e.getMessage() != null && "Macro cancelled".equals(e.getMessage())) { - IJ.run("Close"); - } - IJ.error(e.getMessage()); - } finally { - if (!finished) { - setDone(); - setProgress("An unexpected error occurred."); - } - if (listener != null) listener.onThreadFinished(); - rm.setVisible(true); - rm.close(); - } + public boolean shouldSaveImage() { + return saveImage; } /** - * Deletes all owned ROIs from an image on OMERO. + * Sets whether the images should be saved or not. * - * @param image The image on OMERO. + * @param saveImage See above. */ - private void deleteROIs(ImageWrapper image) { - setState("ROIs deletion from OMERO"); - try { - List rois = image.getROIs(client); - for (ROIWrapper roi : rois) { - if (roi.getOwner().getId() == client.getId()) { - client.delete(roi); - } - } - } catch (ExecutionException | OMEROServerError | ServiceException | AccessException exception) { - LOGGER.warning(exception.getMessage()); - } catch (InterruptedException e) { - LOGGER.warning(e.getMessage()); - Thread.currentThread().interrupt(); - } + public void setSaveImage(boolean saveImage) { + this.saveImage = saveImage; } /** - * Retrieves the list of ROIs from the ROI manager. - * - * @param imp The image ROIs are linked to. + * Returns whether the ROIs should be loaded or not. * * @return See above. */ - private List getManagedRois(ImagePlus imp) { - List ijRois = new ArrayList<>(Arrays.asList(rm.getRoisAsArray())); - for (Roi roi : ijRois) roi.setImage(imp); - return ijRois; + public boolean shouldLoadROIs() { + return loadROIs; } /** - * Converts ROIs from the ROI Manager to OMERO ROIs. - * - * @param imp The image ROIs are linked to. - * @param property The ROI property used to group shapes in OMERO. + * Sets whether the ROIs should be loaded or not. * - * @return A list of OMERO ROIs. + * @param loadROIs See above. */ - private List getROIsFromManager(ImagePlus imp, String property) { - List rois = new ArrayList<>(0); - if (imp != null) { - List ijRois = getManagedRois(imp); - rois = ROIWrapper.fromImageJ(ijRois, property); - } - - return rois; + public void setLoadROIS(boolean loadROIs) { + this.loadROIs = loadROIs; } /** - * Runs a macro on images and saves the results. + * Returns whether the ROIs should be cleared or not. + * + * @return See above. */ - void runMacro() { - String property = ROIWrapper.IJ_PROPERTY; - WindowManager.closeAllWindows(); - - // Initialize ROI Manager - initRoiManager(); - ROIMode roiMode = ROIMode.DO_NOT_LOAD; - if (loadROIs) { - roiMode = ROIMode.MANAGER; - } - - int index = 0; - for (BatchImage image : images) { - setProgress("Image " + (index + 1) + "/" + images.size()); - ImagePlus imp = image.getImagePlus(roiMode); - // If image could not be loaded, continue to next image. - if (imp != null) { - ImageWrapper imageWrapper = image.getImageWrapper(); - Long inputImageId = imageWrapper != null ? imageWrapper.getId() : null; - imp.show(); - - // Process the image - script.setImage(imp); - script.run(); - - imp.changes = false; // Prevent "Save Changes?" dialog - save(imp, inputImageId, property); - } - closeWindows(); - index++; - } + public boolean shouldClearROIs() { + return clearROIs; } /** - * Loads ROIs from an image in OMERO into ImageJ. + * Sets whether the ROIs should be cleared or not. * - * @param image The OMERO image. - * @param imp The image in ImageJ ROIs should be linked to. - * @param toOverlay Whether the ROIs should be loaded to the ROI Manager (false) or the overlay (true). + * @param clearROIs See above. */ - private void loadROIs(ImageWrapper image, ImagePlus imp, boolean toOverlay) { - List ijRois = new ArrayList<>(0); - try { - ijRois = ROIWrapper.toImageJ(image.getROIs(client)); - } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Could not load ROIs: " + e.getMessage()); - } - if (toOverlay) { - Overlay overlay = imp.getOverlay(); - if (overlay != null) { - overlay.clear(); - } else { - overlay = new Overlay(); - } - for (Roi ijRoi : ijRois) { - ijRoi.setImage(imp); - overlay.add(ijRoi, ijRoi.getName()); - } - } else { - rm.reset(); // Reset ROI manager to clear previous ROIs - for (Roi ijRoi : ijRois) { - ijRoi.setImage(imp); - rm.addRoi(ijRoi); - } - } + public void setClearROIS(boolean clearROIs) { + this.clearROIs = clearROIs; } /** - * Saves the images, results and ROIs. + * Returns the output directory. * - * @param inputImage The input image in ImageJ. - * @param omeroInputId The OMERO image input ID. - * @param property The ROI property used to group shapes in OMERO. + * @return See above. */ - private void save(ImagePlus inputImage, Long omeroInputId, String property) { - String inputTitle = removeExtension(inputImage.getTitle()); - - Long omeroOutputId = omeroInputId; - List outputs = getOutputImages(inputImage); - - ImagePlus outputImage = inputImage; - if (!outputs.isEmpty()) outputImage = outputs.get(0); - - // If input image is expected as output for ROIs on OMERO but is not annotable, import it. - boolean annotable = Boolean.parseBoolean(inputImage.getProp("Annotable")); - boolean outputIsNotInput = !inputImage.equals(outputImage); - if (!outputOnOMERO || !saveROIs || annotable || outputIsNotInput) { - outputs.removeIf(inputImage::equals); - } - - if (saveImage) { - if (outputs.isEmpty()) LOGGER.info("Warning: there is no new image."); - List outputIds = new ArrayList<>(outputs.size()); - outputs.forEach(imp -> outputIds.addAll(saveImage(imp, property))); - if (!outputIds.isEmpty() && outputIsNotInput) { - omeroOutputId = outputIds.get(0); - } - } - - if (saveROIs) { - if (!saveImage) saveOverlay(outputImage, omeroOutputId, inputTitle, property); - saveROIManager(outputImage, omeroOutputId, inputTitle, property); - } - if (saveResults) saveResults(outputImage, omeroOutputId, inputTitle, property); - if (saveLog) saveLog(omeroOutputId, inputTitle); - - for (ImagePlus imp : outputs) { - imp.changes = false; - imp.close(); - } + public String getDirectoryOut() { + return directoryOut; } /** - * Saves an image. + * Sets the output directory. * - * @param image The image to save. - * @param property The ROI property to group shapes in OMERO. - * - * @return The OMERO IDs of the (possibly) uploaded image. Should be empty or contain one value. + * @param directoryOut See above. */ - private List saveImage(ImagePlus image, String property) { - List ids = new ArrayList<>(0); - String title = removeExtension(image.getTitle()); - String path = directoryOut + File.separator + title + suffix + ".tif"; - IJ.saveAsTiff(image, path); - if (outputOnOMERO) { - try { - setState("Import on OMERO..."); - DatasetWrapper dataset = client.getDataset(outputDatasetId); - ids = dataset.importImage(client, path); - if (saveROIs && !ids.isEmpty()) { - saveOverlay(image, ids.get(0), title, property); - } - } catch (AccessException | ServiceException | OMEROServerError | ExecutionException e) { - IJ.error("Could not import image: " + e.getMessage()); - } - } - return ids; + public void setDirectoryOut(String directoryOut) { + this.directoryOut = directoryOut; } /** - * Saves the ROIs from an image overlay in ImageJ. + * Returns the suffix to append to the output files. * - * @param imp The image. - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. - * @param property The ROI property used to group shapes on OMERO. + * @return See above. */ - private void saveOverlay(ImagePlus imp, Long imageId, String title, String property) { - if (outputOnLocal) { // local save - setState("Saving overlay ROIs..."); - String path = directoryOut + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; - List ijRois = getOverlay(imp); - saveRoiFile(ijRois, path); - } - if (outputOnOMERO && imageId != null) { // save on Omero - List rois = getROIsFromOverlay(imp, property); - try { - ImageWrapper image = client.getImage(imageId); - if (clearROIs) { - deleteROIs(image); - } - setState("Saving overlay ROIs on OMERO..."); - image.saveROIs(client, rois); - loadROIs(image, imp, true); // reload ROIs - } catch (ServiceException | AccessException | ExecutionException e) { - IJ.error("Could not import overlay ROIs to OMERO: " + e.getMessage()); - } - } + public String getSuffix() { + return suffix; } /** - * Saves the ROIs from the ROI Manager (for an image). + * Sets the suffix to append to the output files. * - * @param imp The image. - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. - * @param property The ROI property used to group shapes on OMERO. + * @param suffix See above. */ - private void saveROIManager(ImagePlus imp, Long imageId, String title, String property) { - if (outputOnLocal) { // local save - setState("Saving ROIs..."); - String path = directoryOut + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; - List ijRois = getManagedRois(imp); - saveRoiFile(ijRois, path); - } - if (outputOnOMERO && imageId != null) { // save on Omero - List rois = getROIsFromManager(imp, property); - try { - ImageWrapper image = client.getImage(imageId); - if (clearROIs) { - deleteROIs(image); - } - setState("Saving ROIs on OMERO..."); - image.saveROIs(client, rois); - loadROIs(image, imp, false); // reload ROIs - } catch (ServiceException | AccessException | ExecutionException e) { - IJ.error("Could not import ROIs to OMERO: " + e.getMessage()); - } - } + public void setSuffix(String suffix) { + this.suffix = suffix; } /** - * Saves the results (linked to an image). + * Returns whether the output will be on OMERO or not. * - * @param imp The image. - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. - * @param property The ROI property used to group shapes on OMERO. + * @return See above. */ - private void saveResults(ImagePlus imp, Long imageId, String title, String property) { - List ijRois = getOverlay(imp); - ijRois.addAll(getManagedRois(imp)); - - setState("Saving results files..."); - String[] candidates = WindowManager.getNonImageTitles(); - List results = Arrays.stream(candidates) - .map(ResultsTable::getResultsTable) - .collect(Collectors.toList()); - results.add(0, ResultsTable.getResultsTable()); - Map processed = new HashMap<>(results.size()); - for (ResultsTable rt : results) { - if (rt != null) { - String name = rt.getTitle(); - if (!Boolean.TRUE.equals(processed.get(name)) && rt.getHeadings().length > 0) { - String path = directoryOut + File.separator + name + "_" + title + "_" + timestamp() + ".csv"; - rt.save(path); - if (outputOnOMERO) { - appendTable(rt, imageId, ijRois, property); - uploadFile(imageId, path); - } - rt.reset(); - processed.put(name, true); - } - } - } + public boolean isOutputOnOMERO() { + return outputOnOMERO; } /** - * Saves the log. + * Sets whether the output will be on OMERO or not. * - * @param imageId The image ID on OMERO. - * @param title The image title used to name the file when saving locally. + * @param outputOnOMERO See above. */ - private void saveLog(Long imageId, String title) { - String path = directoryOut + File.separator + title + "_log.txt"; - IJ.selectWindow("Log"); - IJ.saveAs("txt", path); - if (outputOnOMERO) uploadFile(imageId, path); + public void setOutputOnOMERO(boolean outputOnOMERO) { + this.outputOnOMERO = outputOnOMERO; } /** - * Uploads a file to an image on OMERO. + * Returns whether the output will be saved locally or not. * - * @param imageId The image ID on OMERO. - * @param path The path to the file. + * @return See above. */ - private void uploadFile(Long imageId, String path) { - if (imageId != null) { - try { - setState("Uploading results files..."); - ImageWrapper image = client.getImage(imageId); - image.addFile(client, new File(path)); - } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Error adding file to image:" + e.getMessage()); - } catch (InterruptedException e) { - IJ.error("Error adding file to image:" + e.getMessage()); - Thread.currentThread().interrupt(); - } - } + public boolean isOutputOnLocal() { + return outputOnLocal; } /** - * Adds the current results to the corresponding table. + * Sets whether the output will be saved locally or not. * - * @param results The results table. - * @param imageId The image ID on OMERO. - * @param ijRois The ROIs in ImageJ. - * @param property The ROI property used to group shapes on OMERO. + * @param outputOnLocal See above. */ - private void appendTable(ResultsTable results, Long imageId, List ijRois, String property) { - String resultsName = results.getTitle(); - TableWrapper table = tables.get(resultsName); - try { - if (table == null) { - tables.put(resultsName, new TableWrapper(client, results, imageId, ijRois, property)); - } else { - table.addRows(client, results, imageId, ijRois, property); - } - } catch (ServiceException | AccessException | ExecutionException e) { - IJ.error("Could not create or append table: " + e.getMessage()); - } + public void setOutputOnLocal(boolean outputOnLocal) { + this.outputOnLocal = outputOnLocal; } /** - * Upload the tables to OMERO. + * Returns whether the log should be saved or not. + * + * @return See above. */ - private void uploadTables() { - if (outputOnOMERO && saveResults) { - setState("Uploading tables..."); - try { - ProjectWrapper project = client.getProject(outputProjectId); - for (Map.Entry entry : tables.entrySet()) { - String name = entry.getKey(); - TableWrapper table = entry.getValue(); - String newName; - if (name == null || name.isEmpty()) newName = timestamp() + "_" + table.getName(); - else newName = timestamp() + "_" + name; - table.setName(newName); - project.addTable(client, table); - String path = directoryOut + File.separator + newName + ".csv"; - table.saveAs(path, 'c'); - project.addFile(client, new File(path)); - } - } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Could not save table: " + e.getMessage()); - } catch (IOException e) { - IJ.error("Could not save table as file: " + e.getMessage()); - } catch (InterruptedException e) { - IJ.error("Could not upload CSV to project: " + e.getMessage()); - Thread.currentThread().interrupt(); - } - } + public boolean shouldSaveLog() { + return this.saveLog; } /** - * Closes all open windows in ImageJ. + * Sets whether the log should be saved or not. + * + * @param saveLog See above. */ - private void closeWindows() { - for (Frame frame : WindowManager.getNonImageWindows()) { - if (frame instanceof TextWindow) { - ((TextWindow) frame).close(false); - } - } - rm.reset(); - WindowManager.closeAllWindows(); - } - - - public Client getClient() { - return client; - } - - - public long getOutputProjectId() { - return outputProjectId; - } - - - public void setOutputProjectId(Long outputProjectId) { - if (outputProjectId != null) this.outputProjectId = outputProjectId; - } - - - public long getOutputDatasetId() { - return outputDatasetId; - } - - - public void setOutputDatasetId(Long outputDatasetId) { - if (outputDatasetId != null) this.outputDatasetId = outputDatasetId; - } - - - public boolean shouldSaveROIs() { - return saveROIs; - } - - - public void setSaveROIs(boolean saveROIs) { - this.saveROIs = saveROIs; - } - - - public boolean shouldSaveResults() { - return saveResults; - } - - - public void setSaveResults(boolean saveResults) { - this.saveResults = saveResults; - } - - - public boolean shouldSaveImage() { - return saveImage; - } - - - public void setSaveImage(boolean saveImage) { - this.saveImage = saveImage; - } - - - public boolean shouldLoadROIs() { - return loadROIs; - } - - - public void setLoadROIS(boolean loadROIs) { - this.loadROIs = loadROIs; - } - - - public boolean shouldClearROIs() { - return clearROIs; - } - - - public void setClearROIS(boolean clearROIs) { - this.clearROIs = clearROIs; - } - - - public String getDirectoryOut() { - return directoryOut; - } - - - public void setDirectoryOut(String directoryOut) { - this.directoryOut = directoryOut; - } - - - public String getSuffix() { - return suffix; - } - - - public void setSuffix(String suffix) { - this.suffix = suffix; - } - - - public boolean isOutputOnOMERO() { - return outputOnOMERO; - } - - - public void setOutputOnOMERO(boolean outputOnOMERO) { - this.outputOnOMERO = outputOnOMERO; - } - - - public boolean isOutputOnLocal() { - return outputOnLocal; - } - - - public void setOutputOnLocal(boolean outputOnLocal) { - this.outputOnLocal = outputOnLocal; - } - - public void setSaveLog(boolean saveLog) { this.saveLog = saveLog; } - - public void setListener(BatchListener listener) { - this.listener = listener; - } - } From e5259023fe39e383b97539dcd3b7139c05d3e781 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 21:03:45 +0100 Subject: [PATCH 17/33] Only keep relevant code in OMEROBatchRunner and OMEROBatchPlugin --- .../fr/igred/ij/macro/OMEROBatchRunner.java | 208 ++++-------------- .../ij/plugin/frame/OMEROBatchPlugin.java | 35 +-- 2 files changed, 62 insertions(+), 181 deletions(-) diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index 73090b2..b87ce65 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -77,39 +77,30 @@ public class OMEROBatchRunner extends Thread { private final ScriptRunner script; private final Client client; private final ProgressMonitor progress; + private final BatchParameters params; private final Map tables = new HashMap<>(5); - private boolean loadROIs; - private boolean saveImage; - private boolean saveROIs; - private boolean saveResults; - private boolean saveLog; - private boolean clearROIs; - private boolean outputOnOMERO; - private boolean outputOnLocal; - private long outputDatasetId; - private long outputProjectId; - private String directoryOut; - private String suffix; - private RoiManager rm; private BatchListener listener; - public OMEROBatchRunner(ScriptRunner script, List images, Client client) { - this(script, images, client, new ProgressLog(LOGGER)); + public OMEROBatchRunner(ScriptRunner script, List images, BatchParameters params, Client client) { + this(script, images, params, client, new ProgressLog(LOGGER)); } - public OMEROBatchRunner(ScriptRunner script, List images, Client client, ProgressMonitor progress) { + public OMEROBatchRunner(ScriptRunner script, + List images, + BatchParameters params, + Client client, + ProgressMonitor progress) { this.script = script; this.images = new ArrayList<>(images); + this.params = new BatchParameters(params); this.client = client; this.progress = progress; - this.suffix = ""; - this.directoryOut = null; this.rm = null; this.listener = null; } @@ -323,9 +314,9 @@ public void run() { } try { - if (!outputOnLocal) { + if (!params.isOutputOnLocal()) { setState("Temporary directory creation..."); - directoryOut = Files.createTempDirectory("Fiji_analysis").toString(); + params.setDirectoryOut(Files.createTempDirectory("Fiji_analysis").toString()); } setState("Macro running..."); @@ -333,9 +324,9 @@ public void run() { setProgress(""); uploadTables(); - if (!outputOnLocal) { + if (!params.isOutputOnLocal()) { setState("Temporary directory deletion..."); - if (!deleteTemp(directoryOut)) { + if (!deleteTemp(params.getDirectoryOut())) { LOGGER.warning("Temp directory may not be deleted."); } } @@ -428,7 +419,7 @@ void runMacro() { // Initialize ROI Manager initRoiManager(); ROIMode roiMode = ROIMode.DO_NOT_LOAD; - if (loadROIs) { + if (params.shouldLoadROIs()) { roiMode = ROIMode.MANAGER; } @@ -507,13 +498,13 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { if (!outputs.isEmpty()) outputImage = outputs.get(0); // If input image is expected as output for ROIs on OMERO but is not annotable, import it. - boolean annotable = Boolean.parseBoolean(inputImage.getProp("Annotable")); + boolean annotatable = Boolean.parseBoolean(inputImage.getProp("Annotable")); boolean outputIsNotInput = !inputImage.equals(outputImage); - if (!outputOnOMERO || !saveROIs || annotable || outputIsNotInput) { + if (!params.isOutputOnOMERO() || !params.shouldSaveROIs() || annotatable || outputIsNotInput) { outputs.removeIf(inputImage::equals); } - if (saveImage) { + if (params.shouldSaveImage()) { if (outputs.isEmpty()) LOGGER.info("Warning: there is no new image."); List outputIds = new ArrayList<>(outputs.size()); outputs.forEach(imp -> outputIds.addAll(saveImage(imp, property))); @@ -522,12 +513,12 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { } } - if (saveROIs) { - if (!saveImage) saveOverlay(outputImage, omeroOutputId, inputTitle, property); + if (params.shouldSaveROIs()) { + if (!params.shouldSaveImage()) saveOverlay(outputImage, omeroOutputId, inputTitle, property); saveROIManager(outputImage, omeroOutputId, inputTitle, property); } - if (saveResults) saveResults(outputImage, omeroOutputId, inputTitle, property); - if (saveLog) saveLog(omeroOutputId, inputTitle); + if (params.shouldSaveResults()) saveResults(outputImage, omeroOutputId, inputTitle, property); + if (params.shouldSaveLog()) saveLog(omeroOutputId, inputTitle); for (ImagePlus imp : outputs) { imp.changes = false; @@ -547,14 +538,14 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { private List saveImage(ImagePlus image, String property) { List ids = new ArrayList<>(0); String title = removeExtension(image.getTitle()); - String path = directoryOut + File.separator + title + suffix + ".tif"; + String path = params.getDirectoryOut() + File.separator + title + params.getSuffix() + ".tif"; IJ.saveAsTiff(image, path); - if (outputOnOMERO) { + if (params.isOutputOnOMERO()) { try { setState("Import on OMERO..."); - DatasetWrapper dataset = client.getDataset(outputDatasetId); + DatasetWrapper dataset = client.getDataset(params.getOutputDatasetId()); ids = dataset.importImage(client, path); - if (saveROIs && !ids.isEmpty()) { + if (params.shouldSaveROIs() && !ids.isEmpty()) { saveOverlay(image, ids.get(0), title, property); } } catch (AccessException | ServiceException | OMEROServerError | ExecutionException e) { @@ -574,17 +565,17 @@ private List saveImage(ImagePlus image, String property) { * @param property The ROI property used to group shapes on OMERO. */ private void saveOverlay(ImagePlus imp, Long imageId, String title, String property) { - if (outputOnLocal) { // local save + if (params.isOutputOnLocal()) { // local save setState("Saving overlay ROIs..."); - String path = directoryOut + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; + String path = params.getDirectoryOut() + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; List ijRois = getOverlay(imp); saveRoiFile(ijRois, path); } - if (outputOnOMERO && imageId != null) { // save on Omero + if (params.isOutputOnOMERO() && imageId != null) { // save on Omero List rois = getROIsFromOverlay(imp, property); try { ImageWrapper image = client.getImage(imageId); - if (clearROIs) { + if (params.shouldClearROIs()) { deleteROIs(image); } setState("Saving overlay ROIs on OMERO..."); @@ -606,17 +597,17 @@ private void saveOverlay(ImagePlus imp, Long imageId, String title, String prope * @param property The ROI property used to group shapes on OMERO. */ private void saveROIManager(ImagePlus imp, Long imageId, String title, String property) { - if (outputOnLocal) { // local save + if (params.isOutputOnLocal()) { // local save setState("Saving ROIs..."); - String path = directoryOut + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; + String path = params.getDirectoryOut() + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; List ijRois = getManagedRois(imp); saveRoiFile(ijRois, path); } - if (outputOnOMERO && imageId != null) { // save on Omero + if (params.isOutputOnOMERO() && imageId != null) { // save on Omero List rois = getROIsFromManager(imp, property); try { ImageWrapper image = client.getImage(imageId); - if (clearROIs) { + if (params.shouldClearROIs()) { deleteROIs(image); } setState("Saving ROIs on OMERO..."); @@ -652,9 +643,13 @@ private void saveResults(ImagePlus imp, Long imageId, String title, String prope if (rt != null) { String name = rt.getTitle(); if (!Boolean.TRUE.equals(processed.get(name)) && rt.getHeadings().length > 0) { - String path = directoryOut + File.separator + name + "_" + title + "_" + timestamp() + ".csv"; + String path = params.getDirectoryOut() + + File.separator + + name + "_" + + title + "_" + + timestamp() + ".csv"; rt.save(path); - if (outputOnOMERO) { + if (params.isOutputOnOMERO()) { appendTable(rt, imageId, ijRois, property); uploadFile(imageId, path); } @@ -673,10 +668,10 @@ private void saveResults(ImagePlus imp, Long imageId, String title, String prope * @param title The image title used to name the file when saving locally. */ private void saveLog(Long imageId, String title) { - String path = directoryOut + File.separator + title + "_log.txt"; + String path = params.getDirectoryOut() + File.separator + title + "_log.txt"; IJ.selectWindow("Log"); IJ.saveAs("txt", path); - if (outputOnOMERO) uploadFile(imageId, path); + if (params.isOutputOnOMERO()) uploadFile(imageId, path); } @@ -729,10 +724,10 @@ private void appendTable(ResultsTable results, Long imageId, List ijRois, S * Upload the tables to OMERO. */ private void uploadTables() { - if (outputOnOMERO && saveResults) { + if (params.isOutputOnOMERO() && params.shouldSaveResults()) { setState("Uploading tables..."); try { - ProjectWrapper project = client.getProject(outputProjectId); + ProjectWrapper project = client.getProject(params.getOutputProjectId()); for (Map.Entry entry : tables.entrySet()) { String name = entry.getKey(); TableWrapper table = entry.getValue(); @@ -741,7 +736,7 @@ private void uploadTables() { else newName = timestamp() + "_" + name; table.setName(newName); project.addTable(client, table); - String path = directoryOut + File.separator + newName + ".csv"; + String path = params.getDirectoryOut() + File.separator + newName + ".csv"; table.saveAs(path, 'c'); project.addFile(client, new File(path)); } @@ -776,121 +771,6 @@ public Client getClient() { } - public long getOutputProjectId() { - return outputProjectId; - } - - - public void setOutputProjectId(Long outputProjectId) { - if (outputProjectId != null) this.outputProjectId = outputProjectId; - } - - - public long getOutputDatasetId() { - return outputDatasetId; - } - - - public void setOutputDatasetId(Long outputDatasetId) { - if (outputDatasetId != null) this.outputDatasetId = outputDatasetId; - } - - - public boolean shouldSaveROIs() { - return saveROIs; - } - - - public void setSaveROIs(boolean saveROIs) { - this.saveROIs = saveROIs; - } - - - public boolean shouldSaveResults() { - return saveResults; - } - - - public void setSaveResults(boolean saveResults) { - this.saveResults = saveResults; - } - - - public boolean shouldSaveImage() { - return saveImage; - } - - - public void setSaveImage(boolean saveImage) { - this.saveImage = saveImage; - } - - - public boolean shouldLoadROIs() { - return loadROIs; - } - - - public void setLoadROIS(boolean loadROIs) { - this.loadROIs = loadROIs; - } - - - public boolean shouldClearROIs() { - return clearROIs; - } - - - public void setClearROIS(boolean clearROIs) { - this.clearROIs = clearROIs; - } - - - public String getDirectoryOut() { - return directoryOut; - } - - - public void setDirectoryOut(String directoryOut) { - this.directoryOut = directoryOut; - } - - - public String getSuffix() { - return suffix; - } - - - public void setSuffix(String suffix) { - this.suffix = suffix; - } - - - public boolean isOutputOnOMERO() { - return outputOnOMERO; - } - - - public void setOutputOnOMERO(boolean outputOnOMERO) { - this.outputOnOMERO = outputOnOMERO; - } - - - public boolean isOutputOnLocal() { - return outputOnLocal; - } - - - public void setOutputOnLocal(boolean outputOnLocal) { - this.outputOnLocal = outputOnLocal; - } - - - public void setSaveLog(boolean saveLog) { - this.saveLog = saveLog; - } - - public void setListener(BatchListener listener) { this.listener = listener; } diff --git a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java index 90c0ef0..5ad3bb8 100644 --- a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java +++ b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java @@ -20,6 +20,7 @@ import fr.igred.ij.gui.ProgressDialog; import fr.igred.ij.io.BatchImage; import fr.igred.ij.macro.BatchListener; +import fr.igred.ij.macro.BatchParameters; import fr.igred.ij.macro.OMEROBatchRunner; import fr.igred.ij.macro.ScriptRunner; import fr.igred.omero.Client; @@ -923,7 +924,7 @@ private void previewDataset() { */ public void start(ActionEvent e) { ProgressDialog progress = new ProgressDialog(); - OMEROBatchRunner runner; + BatchParameters params = new BatchParameters(); // initialization of success variables boolean checkInput; @@ -931,6 +932,14 @@ public void start(ActionEvent e) { boolean checkOutput = getOutput(); // input data + params.setSuffix(suffix.getText()); + params.setLoadROIS(checkLoadROIs.isSelected()); + params.setClearROIS(checkDelROIs.isSelected()); + params.setSaveImage(checkImage.isSelected()); + params.setSaveResults(checkResults.isSelected()); + params.setSaveROIs(checkROIs.isSelected()); + params.setSaveLog(checkLog.isSelected()); + List images; long inputDatasetId = -1L; try { @@ -945,17 +954,7 @@ public void start(ActionEvent e) { checkInput = getLocalInput(); images = listImages(directoryIn, recursive.isSelected()); } - runner = new OMEROBatchRunner(script, images, client, progress); - runner.setOutputDatasetId(inputDatasetId); - runner.setListener(this); - - runner.setSuffix(suffix.getText()); - runner.setLoadROIS(checkLoadROIs.isSelected()); - runner.setClearROIS(checkDelROIs.isSelected()); - runner.setSaveImage(checkImage.isSelected()); - runner.setSaveResults(checkResults.isSelected()); - runner.setSaveROIs(checkROIs.isSelected()); - runner.setSaveLog(checkLog.isSelected()); + params.setOutputDatasetId(inputDatasetId); } catch (ServiceException | AccessException | ExecutionException | IOException exception) { IJ.error(exception.getMessage()); return; @@ -966,19 +965,21 @@ public void start(ActionEvent e) { } if (onlineOutput.isSelected()) { - runner.setOutputOnOMERO(true); + params.setOutputOnOMERO(true); if (checkResults.isSelected()) { - runner.setOutputProjectId(outputProjectId); + params.setOutputProjectId(outputProjectId); } if (checkImage.isSelected()) { - runner.setOutputDatasetId(outputDatasetId); + params.setOutputDatasetId(outputDatasetId); } } if (localOutput.isSelected()) { - runner.setOutputOnLocal(true); - runner.setDirectoryOut(directoryOut); + params.setOutputOnLocal(true); + params.setDirectoryOut(directoryOut); } + OMEROBatchRunner runner = new OMEROBatchRunner(script, images, params, client, progress); + runner.setListener(this); start.setEnabled(false); try { runner.start(); From 28062c1a5a212626c05a83b1f28b9351a0f97359 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 21:36:41 +0100 Subject: [PATCH 18/33] Adjust style --- .editorconfig | 49 ++++++------ .../fr/igred/ij/gui/OMEROConnectDialog.java | 2 + .../java/fr/igred/ij/gui/ProgressDialog.java | 8 +- .../java/fr/igred/ij/gui/package-info.java | 2 +- src/main/java/fr/igred/ij/io/BatchImage.java | 4 + .../java/fr/igred/ij/io/LocalBatchImage.java | 13 +++- .../java/fr/igred/ij/io/OMEROBatchImage.java | 2 +- src/main/java/fr/igred/ij/io/ROIMode.java | 1 + .../java/fr/igred/ij/macro/BatchListener.java | 4 +- .../fr/igred/ij/macro/BatchParameters.java | 9 ++- .../fr/igred/ij/macro/OMEROBatchRunner.java | 75 ++++++++++++++----- .../java/fr/igred/ij/macro/ProgressLog.java | 4 +- .../fr/igred/ij/macro/ProgressMonitor.java | 5 +- .../java/fr/igred/ij/macro/ScriptRunner.java | 11 ++- .../java/fr/igred/ij/macro/ScriptRunner2.java | 10 ++- .../java/fr/igred/ij/macro/package-info.java | 2 +- .../ij/plugin/frame/OMEROBatchPlugin.java | 48 +++++++++--- .../igred/ij/plugin/frame/package-info.java | 2 +- .../ij/plugin/frame/OMEROBatchPluginTest.java | 2 +- 19 files changed, 176 insertions(+), 77 deletions(-) diff --git a/.editorconfig b/.editorconfig index d3b2842..03a7a74 100644 --- a/.editorconfig +++ b/.editorconfig @@ -41,20 +41,20 @@ ij_java_array_initializer_new_line_after_left_brace = false ij_java_array_initializer_right_brace_on_new_line = false ij_java_array_initializer_wrap = on_every_item ij_java_assert_statement_colon_on_next_line = false -ij_java_assert_statement_wrap = off +ij_java_assert_statement_wrap = normal ij_java_assignment_wrap = off ij_java_binary_operation_sign_on_next_line = false ij_java_binary_operation_wrap = normal ij_java_blank_lines_after_anonymous_class_header = 0 -ij_java_blank_lines_after_class_header = 0 -ij_java_blank_lines_after_imports = 1 -ij_java_blank_lines_after_package = 1 -ij_java_blank_lines_around_class = 1 +ij_java_blank_lines_after_class_header = 1 +ij_java_blank_lines_after_imports = 2 +ij_java_blank_lines_after_package = 2 +ij_java_blank_lines_around_class = 2 ij_java_blank_lines_around_field = 0 ij_java_blank_lines_around_field_in_interface = 0 ij_java_blank_lines_around_initializer = 1 ij_java_blank_lines_around_method = 2 -ij_java_blank_lines_around_method_in_interface = 1 +ij_java_blank_lines_around_method_in_interface = 2 ij_java_blank_lines_before_class_end = 1 ij_java_blank_lines_before_imports = 1 ij_java_blank_lines_before_method_body = 0 @@ -63,23 +63,23 @@ ij_java_block_brace_style = end_of_line ij_java_block_comment_at_first_column = true ij_java_call_parameters_new_line_after_left_paren = false ij_java_call_parameters_right_paren_on_new_line = false -ij_java_call_parameters_wrap = off +ij_java_call_parameters_wrap = normal ij_java_case_statement_on_separate_line = true ij_java_catch_on_new_line = false ij_java_class_annotation_wrap = split_into_lines ij_java_class_brace_style = end_of_line -ij_java_class_count_to_use_import_on_demand = 11 +ij_java_class_count_to_use_import_on_demand = 20 ij_java_class_names_in_javadoc = 1 ij_java_do_not_indent_top_level_class_members = false ij_java_do_not_wrap_after_single_annotation = false -ij_java_do_while_brace_force = never +ij_java_do_while_brace_force = always ij_java_doc_add_blank_line_after_description = true ij_java_doc_add_blank_line_after_param_comments = true ij_java_doc_add_blank_line_after_return = true ij_java_doc_add_p_tag_on_empty_lines = true ij_java_doc_align_exception_comments = true ij_java_doc_align_param_comments = true -ij_java_doc_do_not_wrap_if_one_line = false +ij_java_doc_do_not_wrap_if_one_line = true ij_java_doc_enable_formatting = true ij_java_doc_enable_leading_asterisks = true ij_java_doc_indent_on_continuation = false @@ -92,19 +92,19 @@ ij_java_doc_param_description_on_new_line = false ij_java_doc_preserve_line_breaks = false ij_java_doc_use_throws_not_exception_tag = true ij_java_else_on_new_line = false -ij_java_enum_constants_wrap = off -ij_java_extends_keyword_wrap = normal +ij_java_enum_constants_wrap = on_every_item +ij_java_extends_keyword_wrap = off ij_java_extends_list_wrap = on_every_item ij_java_field_annotation_wrap = split_into_lines ij_java_finally_on_new_line = false -ij_java_for_brace_force = never +ij_java_for_brace_force = always ij_java_for_statement_new_line_after_left_paren = false ij_java_for_statement_right_paren_on_new_line = false ij_java_for_statement_wrap = on_every_item ij_java_generate_final_locals = false ij_java_generate_final_parameters = false -ij_java_if_brace_force = never -ij_java_imports_layout = *,|,javax.**,java.**,|,$* +ij_java_if_brace_force = always +ij_java_imports_layout = *, |, javax.**, java.**, |, $* ij_java_indent_case_from_switch = true ij_java_insert_inner_class_imports = false ij_java_insert_override_annotation = true @@ -112,15 +112,16 @@ ij_java_keep_blank_lines_before_right_brace = 2 ij_java_keep_blank_lines_between_package_declaration_and_header = 2 ij_java_keep_blank_lines_in_code = 2 ij_java_keep_blank_lines_in_declarations = 2 +ij_java_keep_builder_methods_indents = true ij_java_keep_control_statement_in_one_line = true ij_java_keep_first_column_comment = true ij_java_keep_indents_on_empty_lines = false ij_java_keep_line_breaks = true ij_java_keep_multiple_expressions_in_one_line = false ij_java_keep_simple_blocks_in_one_line = false -ij_java_keep_simple_classes_in_one_line = false -ij_java_keep_simple_lambdas_in_one_line = false -ij_java_keep_simple_methods_in_one_line = false +ij_java_keep_simple_classes_in_one_line = true +ij_java_keep_simple_lambdas_in_one_line = true +ij_java_keep_simple_methods_in_one_line = true # <- For empty methods ij_java_label_indent_absolute = false ij_java_label_indent_size = 0 ij_java_lambda_brace_style = end_of_line @@ -129,10 +130,10 @@ ij_java_line_comment_add_space = false ij_java_line_comment_at_first_column = true ij_java_method_annotation_wrap = split_into_lines ij_java_method_brace_style = end_of_line -ij_java_method_call_chain_wrap = normal +ij_java_method_call_chain_wrap = on_every_item ij_java_method_parameters_new_line_after_left_paren = false ij_java_method_parameters_right_paren_on_new_line = false -ij_java_method_parameters_wrap = on_every_item +ij_java_method_parameters_wrap = normal ij_java_modifier_list_wrap = false ij_java_names_count_to_use_import_on_demand = 11 ij_java_new_line_after_lparen_in_record_header = false @@ -149,7 +150,7 @@ ij_java_replace_null_check = true ij_java_replace_sum_lambda_with_method_ref = true ij_java_resource_list_new_line_after_left_paren = false ij_java_resource_list_right_paren_on_new_line = false -ij_java_resource_list_wrap = normal +ij_java_resource_list_wrap = on_every_item ij_java_rparen_on_new_line_in_record_header = false ij_java_space_after_closing_angle_bracket_in_type_argument = false ij_java_space_after_colon = true @@ -232,16 +233,16 @@ ij_java_ternary_operation_signs_on_next_line = false ij_java_ternary_operation_wrap = normal ij_java_test_name_suffix = Test ij_java_throws_keyword_wrap = normal -ij_java_throws_list_wrap = normal +ij_java_throws_list_wrap = on_every_item ij_java_use_external_annotations = false ij_java_use_fq_class_names = false ij_java_use_relative_indents = false ij_java_use_single_class_imports = true ij_java_variable_annotation_wrap = off ij_java_visibility = public -ij_java_while_brace_force = never +ij_java_while_brace_force = always ij_java_while_on_new_line = false -ij_java_wrap_comments = false +ij_java_wrap_comments = true ij_java_wrap_first_method_in_call_chain = false ij_java_wrap_long_lines = false diff --git a/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java b/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java index 5729c6a..e12d8e2 100644 --- a/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java +++ b/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java @@ -16,6 +16,7 @@ */ package fr.igred.ij.gui; + import fr.igred.omero.Client; import fr.igred.omero.exception.ServiceException; import ij.Prefs; @@ -39,6 +40,7 @@ import static javax.swing.JOptionPane.showMessageDialog; + /** * Connection dialog for OMERO. */ diff --git a/src/main/java/fr/igred/ij/gui/ProgressDialog.java b/src/main/java/fr/igred/ij/gui/ProgressDialog.java index edd31c8..dd19812 100644 --- a/src/main/java/fr/igred/ij/gui/ProgressDialog.java +++ b/src/main/java/fr/igred/ij/gui/ProgressDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 @@ -16,6 +16,7 @@ */ package fr.igred.ij.gui; + import fr.igred.ij.macro.ProgressMonitor; import javax.swing.BoxLayout; @@ -27,10 +28,12 @@ import java.awt.Container; import java.awt.Font; + /** * Progress dialog for batch processing. */ public class ProgressDialog extends JFrame implements ProgressMonitor { + private final JLabel progressLabel = new JLabel("", SwingConstants.CENTER); private final JLabel stateLabel = new JLabel("", SwingConstants.CENTER); private final JButton ok = new JButton("OK"); @@ -48,7 +51,8 @@ public ProgressDialog() { Font progFont = new Font("Arial", Font.BOLD, 12); JLabel warnLabel = new JLabel("", SwingConstants.CENTER); warnLabel - .setText(" Warning:
Image processing can take time
depending on your network rate "); + .setText( + " Warning:
Image processing can take time
depending on your network rate "); warnLabel.setFont(warnFont); progressLabel.setFont(progFont); stateLabel.setFont(progFont); diff --git a/src/main/java/fr/igred/ij/gui/package-info.java b/src/main/java/fr/igred/ij/gui/package-info.java index c13bb54..c9d16a6 100644 --- a/src/main/java/fr/igred/ij/gui/package-info.java +++ b/src/main/java/fr/igred/ij/gui/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 diff --git a/src/main/java/fr/igred/ij/io/BatchImage.java b/src/main/java/fr/igred/ij/io/BatchImage.java index 8e67b44..1adff81 100644 --- a/src/main/java/fr/igred/ij/io/BatchImage.java +++ b/src/main/java/fr/igred/ij/io/BatchImage.java @@ -16,9 +16,11 @@ */ package fr.igred.ij.io; + import fr.igred.omero.repository.ImageWrapper; import ij.ImagePlus; + /** * Interface to open images and retrieve the corresponding image on OMERO, if applicable. */ @@ -31,6 +33,7 @@ public interface BatchImage { */ ImageWrapper getImageWrapper(); + /** * Opens the image and returns the corresponding ImagePlus. * @@ -40,6 +43,7 @@ public interface BatchImage { */ ImagePlus getImagePlus(ROIMode mode); + /** * Opens the image and returns the corresponding ImagePlus, with no ROI. * diff --git a/src/main/java/fr/igred/ij/io/LocalBatchImage.java b/src/main/java/fr/igred/ij/io/LocalBatchImage.java index 9578cc5..3ed534b 100644 --- a/src/main/java/fr/igred/ij/io/LocalBatchImage.java +++ b/src/main/java/fr/igred/ij/io/LocalBatchImage.java @@ -16,6 +16,7 @@ */ package fr.igred.ij.io; + import fr.igred.omero.repository.ImageWrapper; import ij.ImagePlus; import loci.formats.FileStitcher; @@ -33,6 +34,7 @@ import java.util.List; import java.util.logging.Logger; + /** * Image stored in a local file. */ @@ -62,7 +64,9 @@ public LocalBatchImage(String path, Integer index) { */ private static List listFiles(File directory, boolean recursive) { File[] files = directory.listFiles(); - if (files == null) files = EMPTY_FILE_ARRAY; + if (files == null) { + files = EMPTY_FILE_ARRAY; + } List paths = new ArrayList<>(files.length); for (File file : files) { if (!file.isDirectory()) { @@ -100,8 +104,11 @@ public static List listImages(String directory, boolean recursive) t process.execute(); int n = process.getSeriesCount(); FileStitcher fs = process.getFileStitcher(); - if (fs != null) used = Arrays.asList(fs.getUsedFiles()); - else used.add(file); + if (fs != null) { + used = Arrays.asList(fs.getUsedFiles()); + } else { + used.add(file); + } for (int i = 0; i < n; i++) { batchImages.add(new LocalBatchImage(file, i)); } diff --git a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java index 803c216..5de8491 100644 --- a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java +++ b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 diff --git a/src/main/java/fr/igred/ij/io/ROIMode.java b/src/main/java/fr/igred/ij/io/ROIMode.java index 2c3e32d..c97a470 100644 --- a/src/main/java/fr/igred/ij/io/ROIMode.java +++ b/src/main/java/fr/igred/ij/io/ROIMode.java @@ -19,6 +19,7 @@ import loci.plugins.in.ImporterOptions; + /** * Modes used to load ROIs. */ diff --git a/src/main/java/fr/igred/ij/macro/BatchListener.java b/src/main/java/fr/igred/ij/macro/BatchListener.java index 923288b..2a42ec2 100644 --- a/src/main/java/fr/igred/ij/macro/BatchListener.java +++ b/src/main/java/fr/igred/ij/macro/BatchListener.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 @@ -16,8 +16,10 @@ */ package fr.igred.ij.macro; + import java.util.EventListener; + /** * Listens to batch runner thread. */ diff --git a/src/main/java/fr/igred/ij/macro/BatchParameters.java b/src/main/java/fr/igred/ij/macro/BatchParameters.java index 3838ab3..78ee692 100644 --- a/src/main/java/fr/igred/ij/macro/BatchParameters.java +++ b/src/main/java/fr/igred/ij/macro/BatchParameters.java @@ -16,6 +16,7 @@ */ package fr.igred.ij.macro; + /** * Holds the parameters to batch run scripts. */ @@ -83,7 +84,9 @@ public long getOutputProjectId() { * @param outputProjectId See above. */ public void setOutputProjectId(Long outputProjectId) { - if (outputProjectId != null) this.outputProjectId = outputProjectId; + if (outputProjectId != null) { + this.outputProjectId = outputProjectId; + } } @@ -103,7 +106,9 @@ public long getOutputDatasetId() { * @param outputDatasetId See above. */ public void setOutputDatasetId(Long outputDatasetId) { - if (outputDatasetId != null) this.outputDatasetId = outputDatasetId; + if (outputDatasetId != null) { + this.outputDatasetId = outputDatasetId; + } } diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index b87ce65..78dfe8d 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -16,6 +16,7 @@ */ package fr.igred.ij.macro; + import fr.igred.ij.gui.ProgressDialog; import fr.igred.ij.io.BatchImage; import fr.igred.ij.io.ROIMode; @@ -62,6 +63,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; + /** * Runs a script over multiple images retrieved from local files or from OMERO. */ @@ -208,7 +210,9 @@ private static List getOverlay(ImagePlus imp) { if (overlay != null) { ijRois = new ArrayList<>(Arrays.asList(overlay.toArray())); } - for (Roi roi : ijRois) roi.setImage(imp); + for (Roi roi : ijRois) { + roi.setImage(imp); + } return ijRois; } @@ -262,7 +266,9 @@ private static void saveRoiFile(List ijRois, String path) { */ private void initRoiManager() { rm = RoiManager.getInstance2(); - if (rm == null) rm = RoiManager.getRoiManager(); + if (rm == null) { + rm = RoiManager.getRoiManager(); + } rm.setVisible(false); } @@ -273,7 +279,9 @@ private void initRoiManager() { * @param text The text for the current state. */ private void setState(String text) { - if (progress != null) progress.setState(text); + if (progress != null) { + progress.setState(text); + } } @@ -283,7 +291,9 @@ private void setState(String text) { * @param text The text for the current progress. */ private void setProgress(String text) { - if (progress != null) progress.setProgress(text); + if (progress != null) { + progress.setProgress(text); + } } @@ -291,7 +301,9 @@ private void setProgress(String text) { * Signals the process is done. */ private void setDone() { - if (progress != null) progress.setDone(); + if (progress != null) { + progress.setDone(); + } } @@ -346,7 +358,9 @@ public void run() { setDone(); setProgress("An unexpected error occurred."); } - if (listener != null) listener.onThreadFinished(); + if (listener != null) { + listener.onThreadFinished(); + } rm.setVisible(true); rm.close(); } @@ -385,7 +399,9 @@ private void deleteROIs(ImageWrapper image) { */ private List getManagedRois(ImagePlus imp) { List ijRois = new ArrayList<>(Arrays.asList(rm.getRoisAsArray())); - for (Roi roi : ijRois) roi.setImage(imp); + for (Roi roi : ijRois) { + roi.setImage(imp); + } return ijRois; } @@ -495,7 +511,9 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { List outputs = getOutputImages(inputImage); ImagePlus outputImage = inputImage; - if (!outputs.isEmpty()) outputImage = outputs.get(0); + if (!outputs.isEmpty()) { + outputImage = outputs.get(0); + } // If input image is expected as output for ROIs on OMERO but is not annotable, import it. boolean annotatable = Boolean.parseBoolean(inputImage.getProp("Annotable")); @@ -505,7 +523,9 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { } if (params.shouldSaveImage()) { - if (outputs.isEmpty()) LOGGER.info("Warning: there is no new image."); + if (outputs.isEmpty()) { + LOGGER.info("Warning: there is no new image."); + } List outputIds = new ArrayList<>(outputs.size()); outputs.forEach(imp -> outputIds.addAll(saveImage(imp, property))); if (!outputIds.isEmpty() && outputIsNotInput) { @@ -514,11 +534,17 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { } if (params.shouldSaveROIs()) { - if (!params.shouldSaveImage()) saveOverlay(outputImage, omeroOutputId, inputTitle, property); + if (!params.shouldSaveImage()) { + saveOverlay(outputImage, omeroOutputId, inputTitle, property); + } saveROIManager(outputImage, omeroOutputId, inputTitle, property); } - if (params.shouldSaveResults()) saveResults(outputImage, omeroOutputId, inputTitle, property); - if (params.shouldSaveLog()) saveLog(omeroOutputId, inputTitle); + if (params.shouldSaveResults()) { + saveResults(outputImage, omeroOutputId, inputTitle, property); + } + if (params.shouldSaveLog()) { + saveLog(omeroOutputId, inputTitle); + } for (ImagePlus imp : outputs) { imp.changes = false; @@ -538,7 +564,8 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { private List saveImage(ImagePlus image, String property) { List ids = new ArrayList<>(0); String title = removeExtension(image.getTitle()); - String path = params.getDirectoryOut() + File.separator + title + params.getSuffix() + ".tif"; + String path = params.getDirectoryOut() + File.separator + + title + params.getSuffix() + ".tif"; IJ.saveAsTiff(image, path); if (params.isOutputOnOMERO()) { try { @@ -567,7 +594,8 @@ private List saveImage(ImagePlus image, String property) { private void saveOverlay(ImagePlus imp, Long imageId, String title, String property) { if (params.isOutputOnLocal()) { // local save setState("Saving overlay ROIs..."); - String path = params.getDirectoryOut() + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; + String path = params.getDirectoryOut() + File.separator + + title + "_" + timestamp() + "_RoiSet.zip"; List ijRois = getOverlay(imp); saveRoiFile(ijRois, path); } @@ -599,7 +627,8 @@ private void saveOverlay(ImagePlus imp, Long imageId, String title, String prope private void saveROIManager(ImagePlus imp, Long imageId, String title, String property) { if (params.isOutputOnLocal()) { // local save setState("Saving ROIs..."); - String path = params.getDirectoryOut() + File.separator + title + "_" + timestamp() + "_RoiSet.zip"; + String path = params.getDirectoryOut() + File.separator + + title + "_" + timestamp() + "_RoiSet.zip"; List ijRois = getManagedRois(imp); saveRoiFile(ijRois, path); } @@ -671,7 +700,9 @@ private void saveLog(Long imageId, String title) { String path = params.getDirectoryOut() + File.separator + title + "_log.txt"; IJ.selectWindow("Log"); IJ.saveAs("txt", path); - if (params.isOutputOnOMERO()) uploadFile(imageId, path); + if (params.isOutputOnOMERO()) { + uploadFile(imageId, path); + } } @@ -705,7 +736,7 @@ private void uploadFile(Long imageId, String path) { * @param ijRois The ROIs in ImageJ. * @param property The ROI property used to group shapes on OMERO. */ - private void appendTable(ResultsTable results, Long imageId, List ijRois, String property) { + private void appendTable(ResultsTable results, Long imageId, List ijRois, String property) { String resultsName = results.getTitle(); TableWrapper table = tables.get(resultsName); try { @@ -732,11 +763,15 @@ private void uploadTables() { String name = entry.getKey(); TableWrapper table = entry.getValue(); String newName; - if (name == null || name.isEmpty()) newName = timestamp() + "_" + table.getName(); - else newName = timestamp() + "_" + name; + if (name == null || name.isEmpty()) { + newName = timestamp() + "_" + table.getName(); + } else { + newName = timestamp() + "_" + name; + } table.setName(newName); project.addTable(client, table); - String path = params.getDirectoryOut() + File.separator + newName + ".csv"; + String path = params.getDirectoryOut() + File.separator + + newName + ".csv"; table.saveAs(path, 'c'); project.addFile(client, new File(path)); } diff --git a/src/main/java/fr/igred/ij/macro/ProgressLog.java b/src/main/java/fr/igred/ij/macro/ProgressLog.java index 5544b86..4424855 100644 --- a/src/main/java/fr/igred/ij/macro/ProgressLog.java +++ b/src/main/java/fr/igred/ij/macro/ProgressLog.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 @@ -16,9 +16,11 @@ */ package fr.igred.ij.macro; + import java.util.logging.Level; import java.util.logging.Logger; + /** * Logs the progress of the batch process. */ diff --git a/src/main/java/fr/igred/ij/macro/ProgressMonitor.java b/src/main/java/fr/igred/ij/macro/ProgressMonitor.java index ce9f5f0..6844c34 100644 --- a/src/main/java/fr/igred/ij/macro/ProgressMonitor.java +++ b/src/main/java/fr/igred/ij/macro/ProgressMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 @@ -16,6 +16,7 @@ */ package fr.igred.ij.macro; + /** * Monitors the batch process progress. */ @@ -28,6 +29,7 @@ public interface ProgressMonitor { */ void setProgress(String text); + /** * Sets the current state. * @@ -35,6 +37,7 @@ public interface ProgressMonitor { */ void setState(String text); + /** * Signals the process is done. */ diff --git a/src/main/java/fr/igred/ij/macro/ScriptRunner.java b/src/main/java/fr/igred/ij/macro/ScriptRunner.java index b993002..6d34cf1 100644 --- a/src/main/java/fr/igred/ij/macro/ScriptRunner.java +++ b/src/main/java/fr/igred/ij/macro/ScriptRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 @@ -16,10 +16,12 @@ */ package fr.igred.ij.macro; + import ij.IJ; import ij.ImagePlus; import ij.gui.GenericDialog; + /** * Runs an ImageJ macro. */ @@ -69,8 +71,11 @@ private static boolean isSciJavaLoaded() { * @return A new ScriptRunner object. */ public static ScriptRunner createScriptRunner(String path) { - if (isSciJavaLoaded()) return new ScriptRunner2(path); - else return new ScriptRunner(path); + if (isSciJavaLoaded()) { + return new ScriptRunner2(path); + } else { + return new ScriptRunner(path); + } } diff --git a/src/main/java/fr/igred/ij/macro/ScriptRunner2.java b/src/main/java/fr/igred/ij/macro/ScriptRunner2.java index 75b428f..261cbcf 100644 --- a/src/main/java/fr/igred/ij/macro/ScriptRunner2.java +++ b/src/main/java/fr/igred/ij/macro/ScriptRunner2.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 @@ -16,6 +16,7 @@ */ package fr.igred.ij.macro; + import ij.IJ; import ij.ImagePlus; import ij.gui.Overlay; @@ -40,6 +41,7 @@ import java.util.Map; import java.util.stream.Collectors; + /** * Runs an ImageJ2 script. */ @@ -265,10 +267,12 @@ private void addInputs() { ModuleItem newInput = new DefaultMutableModuleItem<>(scriptInfo, input.getKey(), Long.class); scriptInfo.registerInput(newInput); } else if (value.getClass().equals(Double.class)) { - ModuleItem newInput = new DefaultMutableModuleItem<>(scriptInfo, input.getKey(), Double.class); + ModuleItem newInput = new DefaultMutableModuleItem<>(scriptInfo, input.getKey(), + Double.class); scriptInfo.registerInput(newInput); } else { - ModuleItem newInput = new DefaultMutableModuleItem<>(scriptInfo, input.getKey(), String.class); + ModuleItem newInput = new DefaultMutableModuleItem<>(scriptInfo, input.getKey(), + String.class); scriptInfo.registerInput(newInput); } } diff --git a/src/main/java/fr/igred/ij/macro/package-info.java b/src/main/java/fr/igred/ij/macro/package-info.java index 821d0a7..d0189b7 100644 --- a/src/main/java/fr/igred/ij/macro/package-info.java +++ b/src/main/java/fr/igred/ij/macro/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 diff --git a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java index 5ad3bb8..ba2e96a 100644 --- a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java +++ b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java @@ -16,6 +16,7 @@ */ package fr.igred.ij.plugin.frame; + import fr.igred.ij.gui.OMEROConnectDialog; import fr.igred.ij.gui.ProgressDialog; import fr.igred.ij.io.BatchImage; @@ -64,6 +65,7 @@ import static fr.igred.ij.io.OMEROBatchImage.listImages; import static javax.swing.JOptionPane.showMessageDialog; + /** * Main window for the OMERO batch plugin. */ @@ -474,9 +476,13 @@ public static void errorWindow(String message) { */ private static void chooseDirectory(JTextField textField) { String pref = textField.getName(); - if (pref.isEmpty()) pref = "omero.batch." + Prefs.DIR_IMAGE; + if (pref.isEmpty()) { + pref = "omero.batch." + Prefs.DIR_IMAGE; + } String previousDir = textField.getText(); - if (previousDir.isEmpty()) previousDir = Prefs.get(pref, previousDir); + if (previousDir.isEmpty()) { + previousDir = Prefs.get(pref, previousDir); + } JFileChooser outputChoice = new JFileChooser(previousDir); outputChoice.setDialogTitle("Choose the directory"); @@ -559,7 +565,9 @@ private void updateInputProject(ItemEvent e) { for (DatasetWrapper d : this.datasets) { datasetListIn.addItem(format(d.getName(), d.getId(), padName, padId)); } - if (!this.datasets.isEmpty()) datasetListIn.setSelectedIndex(0); + if (!this.datasets.isEmpty()) { + datasetListIn.setSelectedIndex(0); + } } } } @@ -594,7 +602,9 @@ private void updateOutputProject(ItemEvent e) { for (DatasetWrapper d : this.myDatasets) { datasetListOut.addItem(format(d.getName(), d.getId(), padName, padId)); } - if (!this.datasets.isEmpty()) datasetListOut.setSelectedIndex(0); + if (!this.datasets.isEmpty()) { + datasetListOut.setSelectedIndex(0); + } } } } @@ -616,7 +626,9 @@ private void createNewDataset(ActionEvent e) { null, null, null); - if (name == null) return; + if (name == null) { + return; + } try { DatasetWrapper newDataset = project.addDataset(client, name, ""); id = newDataset.getId(); @@ -658,7 +670,9 @@ private void updateUser(ItemEvent e) { int index = userList.getSelectedIndex(); String username = userList.getItemAt(index); long userId = -1; - if (index >= 1) userId = users.get(index - 1).getId(); + if (index >= 1) { + userId = users.get(index - 1).getId(); + } userProjectsAndDatasets(username, userId); projectListIn.removeAllItems(); projectListOut.removeAllItems(); @@ -674,8 +688,12 @@ private void updateUser(ItemEvent e) { for (ProjectWrapper project : myProjects) { projectListOut.addItem(format(project.getName(), project.getId(), padMyName, padMyId)); } - if (!userProjects.isEmpty()) projectListIn.setSelectedIndex(0); - if (!myProjects.isEmpty()) projectListOut.setSelectedIndex(0); + if (!userProjects.isEmpty()) { + projectListIn.setSelectedIndex(0); + } + if (!myProjects.isEmpty()) { + projectListOut.setSelectedIndex(0); + } } } @@ -817,7 +835,9 @@ public void onThreadFinished() { private boolean connect() { final Color green = new Color(0, 153, 0); boolean connected = false; - if (client == null) client = new Client(); + if (client == null) { + client = new Client(); + } OMEROConnectDialog connectDialog = new OMEROConnectDialog(); connectDialog.connect(client); if (!connectDialog.wasCancelled()) { @@ -849,7 +869,9 @@ private boolean connect() { int index = -1; for (int i = 0; index < 0 && i < groups.size(); i++) { - if (groups.get(i).getId() == groupId) index = i; + if (groups.get(i).getId() == groupId) { + index = i; + } } groupList.setSelectedIndex(-1); groupList.setSelectedIndex(index); @@ -1138,7 +1160,8 @@ private boolean checkDeleteROIs() { private boolean checkUploadLocalInput() { boolean check = true; if (local.isSelected() && onlineOutput.isSelected() && !checkImage.isSelected()) { - errorWindow(String.format("Output:%nYou can't upload results file or ROIs on OMERO if your image isn't in OMERO")); + errorWindow(String.format( + "Output:%nYou can't upload results file or ROIs on OMERO if your image isn't in OMERO")); check = false; } return check; @@ -1200,7 +1223,8 @@ private void repack() { Container inputPanel = input1b.getParent(); inputPanel.setMinimumSize(inputPanel.getPreferredSize()); - inputPanel.setMaximumSize(new Dimension(inputPanel.getMaximumSize().width, inputPanel.getPreferredSize().height)); + inputPanel.setMaximumSize( + new Dimension(inputPanel.getMaximumSize().width, inputPanel.getPreferredSize().height)); Container outputPanel = output2.getParent(); outputPanel.setMinimumSize(outputPanel.getPreferredSize()); diff --git a/src/main/java/fr/igred/ij/plugin/frame/package-info.java b/src/main/java/fr/igred/ij/plugin/frame/package-info.java index fe5949d..f0c7ee6 100644 --- a/src/main/java/fr/igred/ij/plugin/frame/package-info.java +++ b/src/main/java/fr/igred/ij/plugin/frame/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 diff --git a/src/test/java/fr/igred/ij/plugin/frame/OMEROBatchPluginTest.java b/src/test/java/fr/igred/ij/plugin/frame/OMEROBatchPluginTest.java index 1c20d2e..6869f83 100644 --- a/src/test/java/fr/igred/ij/plugin/frame/OMEROBatchPluginTest.java +++ b/src/test/java/fr/igred/ij/plugin/frame/OMEROBatchPluginTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 MICA & GReD + * Copyright (C) 2021-2023 MICA & GReD * * 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 From 6df63b37d1dfd97a00e3a3d9b3f7211a4701d4dd Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 21:37:15 +0100 Subject: [PATCH 19/33] Improve ROI deletion, loading and information displayed --- src/main/java/fr/igred/ij/io/OMEROBatchImage.java | 8 ++++---- .../java/fr/igred/ij/macro/OMEROBatchRunner.java | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java index 5de8491..f4f9196 100644 --- a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java +++ b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java @@ -16,6 +16,7 @@ */ package fr.igred.ij.io; + import fr.igred.omero.Client; import fr.igred.omero.exception.AccessException; import fr.igred.omero.exception.ServiceException; @@ -34,6 +35,7 @@ import java.util.logging.Logger; import java.util.stream.Collectors; + /** * Image from OMERO. */ @@ -87,9 +89,7 @@ public ImagePlus getImagePlus(ROIMode mode) { imp = imageWrapper.toImagePlus(client); // Store image "annotate" permissions as a property in the ImagePlus object imp.setProp("Annotatable", String.valueOf(imageWrapper.canAnnotate())); - if (imp != null) { - loadROIs(imp, mode); - } + loadROIs(imp, mode); } catch (ExecutionException | ServiceException | AccessException e) { LOGGER.severe("Could not load image: " + e.getMessage()); } @@ -114,7 +114,7 @@ private void loadROIs(ImagePlus imp, ROIMode roiMode) { } catch (ExecutionException | ServiceException | AccessException e) { LOGGER.severe("Could not load ROIs: " + e.getMessage()); } - if (roiMode == ROIMode.OVERLAY) { + if (roiMode == ROIMode.OVERLAY && imp != null) { Overlay overlay = imp.getOverlay(); if (overlay != null) { overlay.clear(); diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index 78dfe8d..bbb9063 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -376,11 +376,8 @@ private void deleteROIs(ImageWrapper image) { setState("ROIs deletion from OMERO"); try { List rois = image.getROIs(client); - for (ROIWrapper roi : rois) { - if (roi.getOwner().getId() == client.getId()) { - client.delete(roi); - } - } + rois.removeIf(roi -> roi.getOwner().getId() != client.getId()); + client.delete(rois); } catch (ExecutionException | OMEROServerError | ServiceException | AccessException exception) { LOGGER.warning(exception.getMessage()); } catch (InterruptedException e) { @@ -441,7 +438,9 @@ void runMacro() { int index = 0; for (BatchImage image : images) { + //noinspection HardcodedFileSeparator setProgress("Image " + (index + 1) + "/" + images.size()); + setState("Opening image..."); ImagePlus imp = image.getImagePlus(roiMode); // If image could not be loaded, continue to next image. if (imp != null) { @@ -450,6 +449,7 @@ void runMacro() { imp.show(); // Process the image + setState("Processing image..."); script.setImage(imp); script.run(); @@ -515,8 +515,8 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { outputImage = outputs.get(0); } - // If input image is expected as output for ROIs on OMERO but is not annotable, import it. - boolean annotatable = Boolean.parseBoolean(inputImage.getProp("Annotable")); + // If input image is expected as output for ROIs on OMERO but is not annotatable, import it. + boolean annotatable = Boolean.parseBoolean(inputImage.getProp("Annotatable")); boolean outputIsNotInput = !inputImage.equals(outputImage); if (!params.isOutputOnOMERO() || !params.shouldSaveROIs() || annotatable || outputIsNotInput) { outputs.removeIf(inputImage::equals); From f088d97d0b398a755c6b77ca0861f5e852ff594e Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 22:28:09 +0100 Subject: [PATCH 20/33] Improve Javadoc --- .../fr/igred/ij/gui/OMEROConnectDialog.java | 10 +++- .../java/fr/igred/ij/gui/ProgressDialog.java | 5 ++ .../java/fr/igred/ij/io/LocalBatchImage.java | 10 ++++ .../java/fr/igred/ij/io/OMEROBatchImage.java | 9 +++ .../fr/igred/ij/macro/BatchParameters.java | 24 +++++--- .../fr/igred/ij/macro/OMEROBatchRunner.java | 55 +++++++++++++++--- .../java/fr/igred/ij/macro/ScriptRunner.java | 3 + .../java/fr/igred/ij/macro/ScriptRunner2.java | 4 ++ .../ij/plugin/frame/OMEROBatchPlugin.java | 57 +++++++++++++++++-- 9 files changed, 153 insertions(+), 24 deletions(-) diff --git a/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java b/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java index e12d8e2..6b6cceb 100644 --- a/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java +++ b/src/main/java/fr/igred/ij/gui/OMEROConnectDialog.java @@ -46,13 +46,21 @@ */ public class OMEROConnectDialog extends JDialog implements ActionListener { + /** The host field. */ private final JTextField hostField = new JTextField(""); + /** The port field. */ private final JFormattedTextField portField = new JFormattedTextField(NumberFormat.getIntegerInstance()); + /** The user field. */ private final JTextField userField = new JTextField(""); + /** The password field. */ private final JPasswordField passwordField = new JPasswordField(""); + /** The login button. */ private final JButton login = new JButton("Login"); + /** The cancel button. */ private final JButton cancel = new JButton("Cancel"); + /** The client. */ private transient Client client; + /** True if cancel was pressed. */ private boolean cancelled = false; @@ -60,8 +68,6 @@ public class OMEROConnectDialog extends JDialog implements ActionListener { * Creates a new dialog to connect the specified client, but does not display it. */ public OMEROConnectDialog() { - super(); - final int width = 350; final int height = 200; diff --git a/src/main/java/fr/igred/ij/gui/ProgressDialog.java b/src/main/java/fr/igred/ij/gui/ProgressDialog.java index dd19812..b2e3bf9 100644 --- a/src/main/java/fr/igred/ij/gui/ProgressDialog.java +++ b/src/main/java/fr/igred/ij/gui/ProgressDialog.java @@ -34,8 +34,13 @@ */ public class ProgressDialog extends JFrame implements ProgressMonitor { + /** The progress label. */ private final JLabel progressLabel = new JLabel("", SwingConstants.CENTER); + + /** The state label. */ private final JLabel stateLabel = new JLabel("", SwingConstants.CENTER); + + /** The OK button. */ private final JButton ok = new JButton("OK"); diff --git a/src/main/java/fr/igred/ij/io/LocalBatchImage.java b/src/main/java/fr/igred/ij/io/LocalBatchImage.java index 3ed534b..793fea4 100644 --- a/src/main/java/fr/igred/ij/io/LocalBatchImage.java +++ b/src/main/java/fr/igred/ij/io/LocalBatchImage.java @@ -40,14 +40,24 @@ */ public class LocalBatchImage implements BatchImage { + /** The logger. */ private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName()); + /** Empty file array defined once. */ private static final File[] EMPTY_FILE_ARRAY = new File[0]; + /** The path to the image. */ private final String path; + /** The image index. */ private final Integer index; + /** + * Creates a new instance with the specified path and index. + * + * @param path The path. + * @param index The image index. + */ public LocalBatchImage(String path, Integer index) { this.path = path; this.index = index; diff --git a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java index f4f9196..8cdf19f 100644 --- a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java +++ b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java @@ -41,12 +41,21 @@ */ public class OMEROBatchImage implements BatchImage { + /** The logger. */ private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName()); + /** The OMERO client. */ private final Client client; + /** The OMERO image. */ private final ImageWrapper imageWrapper; + /** + * Creates a new instance with the specified client and image. + * + * @param client The OMERO client. + * @param imageWrapper The OMERO image. + */ public OMEROBatchImage(Client client, ImageWrapper imageWrapper) { this.client = client; this.imageWrapper = imageWrapper; diff --git a/src/main/java/fr/igred/ij/macro/BatchParameters.java b/src/main/java/fr/igred/ij/macro/BatchParameters.java index 78ee692..44b7feb 100644 --- a/src/main/java/fr/igred/ij/macro/BatchParameters.java +++ b/src/main/java/fr/igred/ij/macro/BatchParameters.java @@ -23,7 +23,7 @@ public class BatchParameters { private boolean loadROIs; - private boolean saveImage; + private boolean saveImages; private boolean saveROIs; private boolean saveResults; private boolean saveLog; @@ -36,9 +36,12 @@ public class BatchParameters { private String suffix; + /** + * Default constructor. + */ public BatchParameters() { this.loadROIs = false; - this.saveImage = false; + this.saveImages = false; this.saveROIs = false; this.saveResults = false; this.saveLog = false; @@ -52,9 +55,14 @@ public BatchParameters() { } + /** + * Copy constructor. + * + * @param parameters The parameters to copy. + */ public BatchParameters(BatchParameters parameters) { this.loadROIs = parameters.loadROIs; - this.saveImage = parameters.saveImage; + this.saveImages = parameters.saveImages; this.saveROIs = parameters.saveROIs; this.saveResults = parameters.saveResults; this.saveLog = parameters.saveLog; @@ -157,18 +165,18 @@ public void setSaveResults(boolean saveResults) { * * @return See above. */ - public boolean shouldSaveImage() { - return saveImage; + public boolean shouldSaveImages() { + return saveImages; } /** * Sets whether the images should be saved or not. * - * @param saveImage See above. + * @param saveImages See above. */ - public void setSaveImage(boolean saveImage) { - this.saveImage = saveImage; + public void setSaveImages(boolean saveImages) { + this.saveImages = saveImages; } diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index bbb9063..196d143 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -44,10 +44,10 @@ import java.io.BufferedOutputStream; import java.io.DataOutputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.file.Files; +import java.nio.file.Paths; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; @@ -63,36 +63,66 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import static java.nio.file.Files.newOutputStream; + /** * Runs a script over multiple images retrieved from local files or from OMERO. */ public class OMEROBatchRunner extends Thread { + /** The logger. */ private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName()); + /** The empty int array. */ private static final int[] EMPTY_INT_ARRAY = new int[0]; + /** The pattern to remove the file extension from an image title. */ private static final Pattern TITLE_AFTER_EXT = Pattern.compile("\\w+\\s?\\[?([^\\[\\]]*)]?"); + /** The images. */ private final List images; + /** The script. */ private final ScriptRunner script; + /** The OMERO client. */ private final Client client; + /** The progress monitor. */ private final ProgressMonitor progress; + /** The parameters. */ private final BatchParameters params; + /** The tables. */ private final Map tables = new HashMap<>(5); + /** The ROI manager. */ private RoiManager rm; + /** The listener. */ private BatchListener listener; + /** + * Creates a new instance with the specified script, images and parameters. + * + * @param script The script. + * @param images The images. + * @param params The parameters. + * @param client The OMERO client. + */ public OMEROBatchRunner(ScriptRunner script, List images, BatchParameters params, Client client) { this(script, images, params, client, new ProgressLog(LOGGER)); } + /** + * Creates a new instance with the specified script, images, parameters and progress monitor. + * + * @param script The script. + * @param images The images. + * @param params The parameters. + * @param client The OMERO client. + * @param progress The progress monitor. + */ public OMEROBatchRunner(ScriptRunner script, List images, BatchParameters params, @@ -125,6 +155,7 @@ private static String timestamp() { * * @return The title, without the extension. */ + @SuppressWarnings("MagicCharacter") private static String removeExtension(String title) { if (title != null) { int index = title.lastIndexOf('.'); @@ -243,7 +274,7 @@ private static List getROIsFromOverlay(ImagePlus imp, String propert * @param path The path to the file. */ private static void saveRoiFile(List ijRois, String path) { - try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(path))); + try (ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(newOutputStream(Paths.get(path)))); DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(zos))) { RoiEncoder re = new RoiEncoder(dos); for (int i = 0; i < ijRois.size(); i++) { @@ -308,10 +339,8 @@ private void setDone() { /** - * If this thread was constructed using a separate - * {@code Runnable} run object, then that - * {@code Runnable} object's {@code run} method is called; - * otherwise, this method does nothing and returns. + * If this thread was constructed using a separate {@code Runnable} run object, then that {@code Runnable} object's + * {@code run} method is called; otherwise, this method does nothing and returns. *

* Subclasses of {@code Thread} should override this method. * @@ -522,7 +551,7 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { outputs.removeIf(inputImage::equals); } - if (params.shouldSaveImage()) { + if (params.shouldSaveImages()) { if (outputs.isEmpty()) { LOGGER.info("Warning: there is no new image."); } @@ -534,7 +563,7 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { } if (params.shouldSaveROIs()) { - if (!params.shouldSaveImage()) { + if (!params.shouldSaveImages()) { saveOverlay(outputImage, omeroOutputId, inputTitle, property); } saveROIManager(outputImage, omeroOutputId, inputTitle, property); @@ -801,11 +830,21 @@ private void closeWindows() { } + /** + * Returns the client. + * + * @return See above. + */ public Client getClient() { return client; } + /** + * Sets the listener. + * + * @param listener The listener. + */ public void setListener(BatchListener listener) { this.listener = listener; } diff --git a/src/main/java/fr/igred/ij/macro/ScriptRunner.java b/src/main/java/fr/igred/ij/macro/ScriptRunner.java index 6d34cf1..18aff0f 100644 --- a/src/main/java/fr/igred/ij/macro/ScriptRunner.java +++ b/src/main/java/fr/igred/ij/macro/ScriptRunner.java @@ -27,7 +27,9 @@ */ public class ScriptRunner { + /** The path to the macro. */ private final String path; + /** The arguments for the macro. */ private String arguments = ""; @@ -114,6 +116,7 @@ public void setArguments(String arguments) { * * @return See above. */ + @SuppressWarnings("MagicCharacter") public String getLanguage() { return path.substring(path.lastIndexOf('.')); } diff --git a/src/main/java/fr/igred/ij/macro/ScriptRunner2.java b/src/main/java/fr/igred/ij/macro/ScriptRunner2.java index 261cbcf..d232f37 100644 --- a/src/main/java/fr/igred/ij/macro/ScriptRunner2.java +++ b/src/main/java/fr/igred/ij/macro/ScriptRunner2.java @@ -47,9 +47,13 @@ */ public class ScriptRunner2 extends ScriptRunner { + /** Whether inputs were detected. */ private final boolean detectedInputs; + /** The inputs. */ protected Map inputs; + /** The script. */ private ScriptModule script; + /** The script language. */ private String language = ""; diff --git a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java index ba2e96a..1868c23 100644 --- a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java +++ b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java @@ -71,20 +71,27 @@ */ public class OMEROBatchPlugin extends PlugInFrame implements BatchListener { + /** The logger. */ private static final Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName()); + /** The format used to display OMERO objects. */ private static final String FORMAT = "%%-%ds (ID:%%%dd)"; - // minimum window size + /** The minimum window size */ private final Dimension minimumSize = new Dimension(640, 480); // connection management + /** The connection status. */ private final JLabel connectionStatus = new JLabel("Disconnected"); + /** The connection button. */ private final JButton connect = new JButton("Connect"); + /** The disconnection button. */ private final JButton disconnect = new JButton("Disconnect"); // source selection + /** The OMERO input button. */ private final JRadioButton omero = new JRadioButton("OMERO"); + /** The local input button. */ private final JRadioButton local = new JRadioButton("Local"); // choices of input images @@ -94,60 +101,96 @@ public class OMEROBatchPlugin extends PlugInFrame implements BatchListener { private final JPanel input2 = new JPanel(); // group and user selection + /** The list of groups. */ private final JComboBox groupList = new JComboBox<>(); + /** The list of users. */ private final JComboBox userList = new JComboBox<>(); // choice of the dataSet + /** The list of projects. */ private final JComboBox projectListIn = new JComboBox<>(); + /** The list of datasets. */ private final JComboBox datasetListIn = new JComboBox<>(); - private final JCheckBox checkDelROIs = new JCheckBox(" Clear ROIs each time "); - private final JCheckBox checkLoadROIs = new JCheckBox(" Load ROIs "); + /** The checkbox to delete ROIs. */ + private final JCheckBox checkDelROIs = new JCheckBox("Clear ROIs each time"); + /** The checkbox to load ROIs. */ + private final JCheckBox checkLoadROIs = new JCheckBox("Load ROIs"); // choice of the record + /** The input folder. */ private final JTextField inputFolder = new JTextField(20); + /** The checkbox to analyse subfolders. */ private final JCheckBox recursive = new JCheckBox("Recursive"); + /** The macro file. */ private final JTextField macro = new JTextField(20); + /** The macro language label. */ private final JLabel labelLanguage = new JLabel(); + /** The macro arguments label. */ private final JLabel labelArguments = new JLabel(); + /** The checkbox to save images. */ private final JCheckBox checkImage = new JCheckBox("New image(s)"); + /** The checkbox to save results. */ private final JCheckBox checkResults = new JCheckBox("Results table(s)"); + /** The checkbox to save ROIs. */ private final JCheckBox checkROIs = new JCheckBox("ROIs"); + /** The checkbox to save the log. */ private final JCheckBox checkLog = new JCheckBox("Log file"); private final JPanel output2 = new JPanel(); + /** The suffix of the output files. */ private final JTextField suffix = new JTextField(10); // Omero or local => checkbox + /** The checkbox to save to OMERO. */ private final JCheckBox onlineOutput = new JCheckBox("OMERO"); + /** The checkbox to save locally. */ private final JCheckBox localOutput = new JCheckBox("Local"); // existing dataset private final JPanel output3a = new JPanel(); + /** The list of possible output projects. */ private final JComboBox projectListOut = new JComboBox<>(); + /** The list of possible output datasets. */ private final JComboBox datasetListOut = new JComboBox<>(); + /** The button to create a new dataset. */ private final JButton newDatasetBtn = new JButton("New"); // local private final JPanel output3b = new JPanel(); + /** The output folder. */ private final JTextField outputFolder = new JTextField(20); - // start button + /** The start button. */ private final JButton start = new JButton("Start"); //variables to keep + /** The OMERO client. */ private transient Client client; + /** The script runner. */ private transient ScriptRunner script; + /** The groups. */ private transient List groups; + /** The group projects. */ private transient List groupProjects; + /** The selected user's projects. */ private transient List userProjects; + /** The datasets. */ private transient List datasets; + /** The current user's projects. */ private transient List myProjects; + /** The current user's datasets. */ private transient List myDatasets; + /** The users. */ private transient List users; + /** The current user. */ private transient ExperimenterWrapper exp; + /** The output directory. */ private String directoryOut = null; + /** The input directory. */ private String directoryIn = null; + /** The output dataset ID. */ private Long outputDatasetId = null; + /** The output project ID. */ private Long outputProjectId = null; @@ -957,7 +1000,7 @@ public void start(ActionEvent e) { params.setSuffix(suffix.getText()); params.setLoadROIS(checkLoadROIs.isSelected()); params.setClearROIS(checkDelROIs.isSelected()); - params.setSaveImage(checkImage.isSelected()); + params.setSaveImages(checkImage.isSelected()); params.setSaveResults(checkResults.isSelected()); params.setSaveROIs(checkROIs.isSelected()); params.setSaveLog(checkLog.isSelected()); @@ -1243,7 +1286,9 @@ private class ClientDisconnector extends WindowAdapter { public void windowClosing(WindowEvent e) { super.windowClosing(e); Client c = client; - if (c != null) c.disconnect(); + if (c != null) { + c.disconnect(); + } } } From 6456dc32102e4f07d54590f24a5200da1de9eabc Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 22:40:06 +0100 Subject: [PATCH 21/33] Fix local processing --- src/main/java/fr/igred/ij/io/LocalBatchImage.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/igred/ij/io/LocalBatchImage.java b/src/main/java/fr/igred/ij/io/LocalBatchImage.java index 793fea4..6aa3c40 100644 --- a/src/main/java/fr/igred/ij/io/LocalBatchImage.java +++ b/src/main/java/fr/igred/ij/io/LocalBatchImage.java @@ -177,7 +177,9 @@ public ImagePlus getImagePlus(ROIMode mode) { try { ImporterOptions options = initImporterOptions(); options.setShowROIs(loadROIs); - options.setROIsMode(mode.toString()); + if (loadROIs) { + options.setROIsMode(mode.toString()); + } options.setId(path); options.setSeriesOn(index, true); ImagePlus[] imps = BF.openImagePlus(options); From 4bea12614f09bb3ea3ceed9b19869eb7bc262bd7 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sat, 4 Nov 2023 23:51:20 +0100 Subject: [PATCH 22/33] Refactor table saving --- .../fr/igred/ij/macro/OMEROBatchRunner.java | 131 +++++++++++++----- 1 file changed, 96 insertions(+), 35 deletions(-) diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index 196d143..f758354 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -20,6 +20,7 @@ import fr.igred.ij.gui.ProgressDialog; import fr.igred.ij.io.BatchImage; import fr.igred.ij.io.ROIMode; +import fr.igred.omero.AnnotatableWrapper; import fr.igred.omero.Client; import fr.igred.omero.annotations.TableWrapper; import fr.igred.omero.exception.AccessException; @@ -44,7 +45,9 @@ import java.io.BufferedOutputStream; import java.io.DataOutputStream; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.lang.invoke.MethodHandles; import java.nio.file.Files; import java.nio.file.Paths; @@ -292,6 +295,40 @@ private static void saveRoiFile(List ijRois, String path) { } + /** + * Adds a timestamp to the table name. + * + * @param table The table. + * @param name The table name. + */ + private static String renameTable(TableWrapper table, String name) { + String newName; + if (name == null || name.isEmpty()) { + newName = timestamp() + "_" + table.getName(); + } else { + newName = timestamp() + "_" + name; + } + table.setName(newName); + return newName; + } + + + /** + * Saves a table as a text file. + * + * @param table The table. + * @param path The path to the file. + */ + private static void saveTable(TableWrapper table, String path) { + try { + //noinspection MagicCharacter + table.saveAs(path, '\t'); + } catch (FileNotFoundException | UnsupportedEncodingException e) { + IJ.error("Could not save table as file: " + e.getMessage()); + } + } + + /** * Initializes the ROI manager. */ @@ -709,8 +746,8 @@ private void saveResults(ImagePlus imp, Long imageId, String title, String prope rt.save(path); if (params.isOutputOnOMERO()) { appendTable(rt, imageId, ijRois, property); - uploadFile(imageId, path); } + uploadFileToImage(imageId, path); rt.reset(); processed.put(name, true); } @@ -729,9 +766,7 @@ private void saveLog(Long imageId, String title) { String path = params.getDirectoryOut() + File.separator + title + "_log.txt"; IJ.selectWindow("Log"); IJ.saveAs("txt", path); - if (params.isOutputOnOMERO()) { - uploadFile(imageId, path); - } + uploadFileToImage(imageId, path); } @@ -741,16 +776,34 @@ private void saveLog(Long imageId, String title) { * @param imageId The image ID on OMERO. * @param path The path to the file. */ - private void uploadFile(Long imageId, String path) { - if (imageId != null) { + private void uploadFileToImage(Long imageId, String path) { + if (imageId != null && params.isOutputOnOMERO()) { + ImageWrapper image = null; try { setState("Uploading results files..."); - ImageWrapper image = client.getImage(imageId); - image.addFile(client, new File(path)); + image = client.getImage(imageId); } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Error adding file to image:" + e.getMessage()); + IJ.error("Error retrieving image:" + e.getMessage()); + } + uploadFile(image, path); + } + } + + + /** + * Uploads a file to an annotatable object on OMERO. + * + * @param object The object on OMERO. + * @param path The path to the file. + */ + private void uploadFile(AnnotatableWrapper object, String path) { + if (object != null && params.isOutputOnOMERO()) { + try { + object.addFile(client, new File(path)); + } catch (ExecutionException e) { + IJ.error("Error adding file to object:" + e.getMessage()); } catch (InterruptedException e) { - IJ.error("Error adding file to image:" + e.getMessage()); + IJ.error("Error adding file to object:" + e.getMessage()); Thread.currentThread().interrupt(); } } @@ -780,37 +833,45 @@ private void appendTable(ResultsTable results, Long imageId, List } + /** + * Uploads a table to a project, if required. + * + * @param project The project the table belongs to. + * @param table The table. + */ + private void uploadTable(ProjectWrapper project, TableWrapper table) { + if (project != null && params.isOutputOnOMERO()) { + try { + project.addTable(client, table); + } catch (ExecutionException | ServiceException | AccessException e) { + IJ.error("Could not upload table: " + e.getMessage()); + } + } + } + + /** * Upload the tables to OMERO. */ private void uploadTables() { - if (params.isOutputOnOMERO() && params.shouldSaveResults()) { + ProjectWrapper project = null; + if (params.shouldSaveResults()) { setState("Uploading tables..."); - try { - ProjectWrapper project = client.getProject(params.getOutputProjectId()); - for (Map.Entry entry : tables.entrySet()) { - String name = entry.getKey(); - TableWrapper table = entry.getValue(); - String newName; - if (name == null || name.isEmpty()) { - newName = timestamp() + "_" + table.getName(); - } else { - newName = timestamp() + "_" + name; - } - table.setName(newName); - project.addTable(client, table); - String path = params.getDirectoryOut() + File.separator + - newName + ".csv"; - table.saveAs(path, 'c'); - project.addFile(client, new File(path)); + if (params.isOutputOnOMERO()) { + try { + project = client.getProject(params.getOutputProjectId()); + } catch (ExecutionException | ServiceException | AccessException e) { + IJ.error("Could not retrieve project: " + e.getMessage()); } - } catch (ExecutionException | ServiceException | AccessException e) { - IJ.error("Could not save table: " + e.getMessage()); - } catch (IOException e) { - IJ.error("Could not save table as file: " + e.getMessage()); - } catch (InterruptedException e) { - IJ.error("Could not upload CSV to project: " + e.getMessage()); - Thread.currentThread().interrupt(); + } + for (Map.Entry entry : tables.entrySet()) { + String name = entry.getKey(); + TableWrapper table = entry.getValue(); + String newName = renameTable(table, name); + uploadTable(project, table); + String path = params.getDirectoryOut() + File.separator + newName + ".csv"; + saveTable(table, path); + uploadFile(project, path); } } } From 8770e86804f4fda20700c409e270b1bc748b12a6 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sun, 5 Nov 2023 00:19:36 +0100 Subject: [PATCH 23/33] Always save concatenated table locally --- src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index f758354..8becf4a 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -744,9 +744,7 @@ private void saveResults(ImagePlus imp, Long imageId, String title, String prope title + "_" + timestamp() + ".csv"; rt.save(path); - if (params.isOutputOnOMERO()) { - appendTable(rt, imageId, ijRois, property); - } + appendTable(rt, imageId, ijRois, property); uploadFileToImage(imageId, path); rt.reset(); processed.put(name, true); From 10e2ee9e5410fb44b09dda3f2e693fabe4a1d189 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sun, 5 Nov 2023 02:01:41 +0100 Subject: [PATCH 24/33] Improve code --- .../fr/igred/ij/macro/OMEROBatchRunner.java | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index 8becf4a..453f867 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -55,6 +55,7 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -386,7 +387,7 @@ private void setDone() { */ @Override public void run() { - boolean finished = false; + boolean running = true; if (progress instanceof ProgressDialog) { ((Component) progress).setVisible(true); } @@ -408,27 +409,29 @@ public void run() { LOGGER.warning("Temp directory may not be deleted."); } } - finished = true; + running = false; setState(""); setDone(); } catch (IOException e) { - finished = true; + running = false; setDone(); setProgress("Macro cancelled"); - if (e.getMessage() != null && "Macro cancelled".equals(e.getMessage())) { + if ("Macro cancelled".equals(e.getMessage())) { IJ.run("Close"); } IJ.error(e.getMessage()); } finally { - if (!finished) { + if (running) { setDone(); setProgress("An unexpected error occurred."); } if (listener != null) { listener.onThreadFinished(); } - rm.setVisible(true); - rm.close(); + if (rm != null) { + rm.setVisible(true); + rm.close(); + } } } @@ -576,12 +579,8 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { Long omeroOutputId = omeroInputId; List outputs = getOutputImages(inputImage); - ImagePlus outputImage = inputImage; - if (!outputs.isEmpty()) { - outputImage = outputs.get(0); - } + ImagePlus outputImage = outputs.isEmpty() ? inputImage : outputs.get(0); - // If input image is expected as output for ROIs on OMERO but is not annotatable, import it. boolean annotatable = Boolean.parseBoolean(inputImage.getProp("Annotatable")); boolean outputIsNotInput = !inputImage.equals(outputImage); if (!params.isOutputOnOMERO() || !params.shouldSaveROIs() || annotatable || outputIsNotInput) { @@ -589,11 +588,7 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { } if (params.shouldSaveImages()) { - if (outputs.isEmpty()) { - LOGGER.info("Warning: there is no new image."); - } - List outputIds = new ArrayList<>(outputs.size()); - outputs.forEach(imp -> outputIds.addAll(saveImage(imp, property))); + List outputIds = saveImages(outputs, property); if (!outputIds.isEmpty() && outputIsNotInput) { omeroOutputId = outputIds.get(0); } @@ -619,6 +614,24 @@ private void save(ImagePlus inputImage, Long omeroInputId, String property) { } + /** + * Saves images. + * + * @param outputs The images to save. + * @param property The ROI property used to group shapes in OMERO. + * + * @return The OMERO IDs of the (possibly) uploaded images. + */ + private List saveImages(Collection outputs, String property) { + if (outputs.isEmpty()) { + LOGGER.info("Warning: there is no new image."); + } + List outputIds = new ArrayList<>(outputs.size()); + outputs.forEach(imp -> outputIds.addAll(saveImage(imp, property))); + return outputIds; + } + + /** * Saves an image. * From 74dbda6c078ed15463453d8b0e8c743aac47622a Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sun, 5 Nov 2023 02:32:12 +0100 Subject: [PATCH 25/33] Fix ROI loading --- .../java/fr/igred/ij/io/OMEROBatchImage.java | 6 ++++-- .../java/fr/igred/ij/macro/OMEROBatchRunner.java | 16 ++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java index 8cdf19f..7adfdfc 100644 --- a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java +++ b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java @@ -98,7 +98,9 @@ public ImagePlus getImagePlus(ROIMode mode) { imp = imageWrapper.toImagePlus(client); // Store image "annotate" permissions as a property in the ImagePlus object imp.setProp("Annotatable", String.valueOf(imageWrapper.canAnnotate())); - loadROIs(imp, mode); + if (mode != ROIMode.DO_NOT_LOAD) { + loadROIs(imp, mode); + } } catch (ExecutionException | ServiceException | AccessException e) { LOGGER.severe("Could not load image: " + e.getMessage()); } @@ -134,7 +136,7 @@ private void loadROIs(ImagePlus imp, ROIMode roiMode) { ijRoi.setImage(imp); overlay.add(ijRoi, ijRoi.getName()); } - } else if (rm != null) { + } else if (roiMode == ROIMode.MANAGER && rm != null) { rm.reset(); // Reset ROI manager to clear previous ROIs for (Roi ijRoi : ijRois) { ijRoi.setImage(imp); diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index 453f867..c4135a0 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -534,18 +534,18 @@ void runMacro() { /** * Loads ROIs from an image in OMERO into ImageJ. * - * @param image The OMERO image. - * @param imp The image in ImageJ ROIs should be linked to. - * @param toOverlay Whether the ROIs should be loaded to the ROI Manager (false) or the overlay (true). + * @param image The OMERO image. + * @param imp The image in ImageJ ROIs should be linked to. + * @param roiMode The mode used to load ROIs. */ - private void loadROIs(ImageWrapper image, ImagePlus imp, boolean toOverlay) { + private void loadROIs(ImageWrapper image, ImagePlus imp, ROIMode roiMode) { List ijRois = new ArrayList<>(0); try { ijRois = ROIWrapper.toImageJ(image.getROIs(client)); } catch (ExecutionException | ServiceException | AccessException e) { IJ.error("Could not load ROIs: " + e.getMessage()); } - if (toOverlay) { + if (roiMode == ROIMode.OVERLAY) { Overlay overlay = imp.getOverlay(); if (overlay != null) { overlay.clear(); @@ -556,7 +556,7 @@ private void loadROIs(ImageWrapper image, ImagePlus imp, boolean toOverlay) { ijRoi.setImage(imp); overlay.add(ijRoi, ijRoi.getName()); } - } else { + } else if (roiMode == ROIMode.MANAGER) { rm.reset(); // Reset ROI manager to clear previous ROIs for (Roi ijRoi : ijRois) { ijRoi.setImage(imp); @@ -687,7 +687,7 @@ private void saveOverlay(ImagePlus imp, Long imageId, String title, String prope } setState("Saving overlay ROIs on OMERO..."); image.saveROIs(client, rois); - loadROIs(image, imp, true); // reload ROIs + loadROIs(image, imp, ROIMode.OVERLAY); // reload ROIs } catch (ServiceException | AccessException | ExecutionException e) { IJ.error("Could not import overlay ROIs to OMERO: " + e.getMessage()); } @@ -720,7 +720,7 @@ private void saveROIManager(ImagePlus imp, Long imageId, String title, String pr } setState("Saving ROIs on OMERO..."); image.saveROIs(client, rois); - loadROIs(image, imp, false); // reload ROIs + loadROIs(image, imp, ROIMode.MANAGER); // reload ROIs } catch (ServiceException | AccessException | ExecutionException e) { IJ.error("Could not import ROIs to OMERO: " + e.getMessage()); } From 9df7e801e613c7c79b6bf9283db8be67ca3043e1 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sun, 5 Nov 2023 02:32:55 +0100 Subject: [PATCH 26/33] Make it possible to load ROIs locally (using Bio-Formats) --- .../java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java index 1868c23..e62a27c 100644 --- a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java +++ b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java @@ -800,14 +800,15 @@ private void updateInput(ItemEvent e) { input1a.setVisible(true); input1b.setVisible(true); input1c.setVisible(true); + input1c.add(checkLoadROIs); input2.setVisible(false); } else { local.setSelected(true); } } else { //local.isSelected() input2.setVisible(true); + input2.add(checkLoadROIs); checkDelROIs.setSelected(false); - checkLoadROIs.setSelected(false); input1c.setVisible(false); input1b.setVisible(false); input1a.setVisible(false); @@ -1277,9 +1278,7 @@ private void repack() { private class ClientDisconnector extends WindowAdapter { - ClientDisconnector() { - super(); - } + ClientDisconnector() {} @Override From 951ff7bce1ace9df7a2df81dbebb072a63c96823 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sun, 5 Nov 2023 11:56:04 +0100 Subject: [PATCH 27/33] Add choice to load ROIs to ROI Manager or Overlay --- .../java/fr/igred/ij/io/LocalBatchImage.java | 2 +- src/main/java/fr/igred/ij/io/ROIMode.java | 6 ++-- .../fr/igred/ij/macro/BatchParameters.java | 19 +++++++----- .../fr/igred/ij/macro/OMEROBatchRunner.java | 8 ++--- .../ij/plugin/frame/OMEROBatchPlugin.java | 29 ++++++++++--------- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/main/java/fr/igred/ij/io/LocalBatchImage.java b/src/main/java/fr/igred/ij/io/LocalBatchImage.java index 6aa3c40..f6e8b26 100644 --- a/src/main/java/fr/igred/ij/io/LocalBatchImage.java +++ b/src/main/java/fr/igred/ij/io/LocalBatchImage.java @@ -173,7 +173,7 @@ public ImageWrapper getImageWrapper() { @Override public ImagePlus getImagePlus(ROIMode mode) { ImagePlus imp = null; - boolean loadROIs = !mode.toString().isEmpty(); + boolean loadROIs = mode != ROIMode.DO_NOT_LOAD; try { ImporterOptions options = initImporterOptions(); options.setShowROIs(loadROIs); diff --git a/src/main/java/fr/igred/ij/io/ROIMode.java b/src/main/java/fr/igred/ij/io/ROIMode.java index c97a470..573dc97 100644 --- a/src/main/java/fr/igred/ij/io/ROIMode.java +++ b/src/main/java/fr/igred/ij/io/ROIMode.java @@ -25,9 +25,9 @@ */ public enum ROIMode { /** - * Do not load ROIs (empty String for ImporterOptions). + * Do not load ROIs. */ - DO_NOT_LOAD(""), + DO_NOT_LOAD("No"), /** * Load ROIs in the ROI Manager. */ @@ -38,7 +38,7 @@ public enum ROIMode { OVERLAY(ImporterOptions.ROIS_MODE_OVERLAY); /** - * ROI mode String value for ImporterOptions. + * ROI mode String value for ImporterOptions and user selection. */ private final String value; diff --git a/src/main/java/fr/igred/ij/macro/BatchParameters.java b/src/main/java/fr/igred/ij/macro/BatchParameters.java index 44b7feb..6090671 100644 --- a/src/main/java/fr/igred/ij/macro/BatchParameters.java +++ b/src/main/java/fr/igred/ij/macro/BatchParameters.java @@ -17,12 +17,15 @@ package fr.igred.ij.macro; +import fr.igred.ij.io.ROIMode; + + /** * Holds the parameters to batch run scripts. */ public class BatchParameters { - private boolean loadROIs; + private ROIMode roiMode; private boolean saveImages; private boolean saveROIs; private boolean saveResults; @@ -40,7 +43,7 @@ public class BatchParameters { * Default constructor. */ public BatchParameters() { - this.loadROIs = false; + this.roiMode = ROIMode.DO_NOT_LOAD; this.saveImages = false; this.saveROIs = false; this.saveResults = false; @@ -61,7 +64,7 @@ public BatchParameters() { * @param parameters The parameters to copy. */ public BatchParameters(BatchParameters parameters) { - this.loadROIs = parameters.loadROIs; + this.roiMode = parameters.roiMode; this.saveImages = parameters.saveImages; this.saveROIs = parameters.saveROIs; this.saveResults = parameters.saveResults; @@ -185,18 +188,18 @@ public void setSaveImages(boolean saveImages) { * * @return See above. */ - public boolean shouldLoadROIs() { - return loadROIs; + public ROIMode getROIMode() { + return roiMode; } /** * Sets whether the ROIs should be loaded or not. * - * @param loadROIs See above. + * @param roiMode See above. */ - public void setLoadROIS(boolean loadROIs) { - this.loadROIs = loadROIs; + public void setROIMode(ROIMode roiMode) { + this.roiMode = roiMode; } diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index c4135a0..223d622 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -494,23 +494,19 @@ private List getROIsFromManager(ImagePlus imp, String property) { /** * Runs a macro on images and saves the results. */ - void runMacro() { + private void runMacro() { String property = ROIWrapper.IJ_PROPERTY; WindowManager.closeAllWindows(); // Initialize ROI Manager initRoiManager(); - ROIMode roiMode = ROIMode.DO_NOT_LOAD; - if (params.shouldLoadROIs()) { - roiMode = ROIMode.MANAGER; - } int index = 0; for (BatchImage image : images) { //noinspection HardcodedFileSeparator setProgress("Image " + (index + 1) + "/" + images.size()); setState("Opening image..."); - ImagePlus imp = image.getImagePlus(roiMode); + ImagePlus imp = image.getImagePlus(params.getROIMode()); // If image could not be loaded, continue to next image. if (imp != null) { ImageWrapper imageWrapper = image.getImageWrapper(); diff --git a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java index e62a27c..3def198 100644 --- a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java +++ b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java @@ -20,6 +20,7 @@ import fr.igred.ij.gui.OMEROConnectDialog; import fr.igred.ij.gui.ProgressDialog; import fr.igred.ij.io.BatchImage; +import fr.igred.ij.io.ROIMode; import fr.igred.ij.macro.BatchListener; import fr.igred.ij.macro.BatchParameters; import fr.igred.ij.macro.OMEROBatchRunner; @@ -97,7 +98,7 @@ public class OMEROBatchPlugin extends PlugInFrame implements BatchListener { // choices of input images private final JPanel input1a = new JPanel(); private final JPanel input1b = new JPanel(); - private final JPanel input1c = new JPanel(); + private final JPanel input3 = new JPanel(); private final JPanel input2 = new JPanel(); // group and user selection @@ -113,8 +114,8 @@ public class OMEROBatchPlugin extends PlugInFrame implements BatchListener { private final JComboBox datasetListIn = new JComboBox<>(); /** The checkbox to delete ROIs. */ private final JCheckBox checkDelROIs = new JCheckBox("Clear ROIs each time"); - /** The checkbox to load ROIs. */ - private final JCheckBox checkLoadROIs = new JCheckBox("Load ROIs"); + /** The list of possible output projects. */ + private final JComboBox roiMode = new JComboBox<>(ROIMode.values()); // choice of the record /** The input folder. */ @@ -286,9 +287,6 @@ public OMEROBatchPlugin() { projectListIn.setFont(listFont); datasetListIn.setFont(listFont); - input1c.add(checkLoadROIs); - input1c.add(checkDelROIs); - JLabel inputFolderLabel = new JLabel("Images folder: "); JButton inputFolderBtn = new JButton(browse); inputFolderLabel.setLabelFor(inputFolder); @@ -300,11 +298,16 @@ public OMEROBatchPlugin() { input2.add(recursive); inputFolderBtn.addActionListener(e -> chooseDirectory(inputFolder)); + JLabel labelROIMode = new JLabel("Load ROIs: "); + input3.add(labelROIMode); + input3.add(roiMode); + input3.add(checkDelROIs); + JPanel panelInput = new JPanel(); panelInput.add(input1a); panelInput.add(input1b); - panelInput.add(input1c); panelInput.add(input2); + panelInput.add(input3); panelInput.setLayout(new BoxLayout(panelInput, BoxLayout.PAGE_AXIS)); panelInput.setBorder(BorderFactory.createTitledBorder("Input")); super.add(panelInput); @@ -422,12 +425,12 @@ public OMEROBatchPlugin() { input2.setVisible(false); input1a.setVisible(true); input1b.setVisible(true); - input1c.setVisible(true); + input3.setVisible(true); super.pack(); input1a.setMaximumSize(new Dimension(input1a.getMaximumSize().width, input1a.getHeight())); input1b.setMaximumSize(new Dimension(input1b.getMaximumSize().width, input1b.getHeight())); - input1c.setMaximumSize(new Dimension(input1c.getMaximumSize().width, input1c.getHeight())); + input3.setMaximumSize(new Dimension(input3.getMaximumSize().width, input3.getHeight())); local.setSelected(true); @@ -799,17 +802,15 @@ private void updateInput(ItemEvent e) { if (connected) { input1a.setVisible(true); input1b.setVisible(true); - input1c.setVisible(true); - input1c.add(checkLoadROIs); input2.setVisible(false); + checkDelROIs.setVisible(true); } else { local.setSelected(true); } } else { //local.isSelected() input2.setVisible(true); - input2.add(checkLoadROIs); checkDelROIs.setSelected(false); - input1c.setVisible(false); + checkDelROIs.setVisible(false); input1b.setVisible(false); input1a.setVisible(false); } @@ -999,7 +1000,7 @@ public void start(ActionEvent e) { // input data params.setSuffix(suffix.getText()); - params.setLoadROIS(checkLoadROIs.isSelected()); + params.setROIMode(roiMode.getItemAt(roiMode.getSelectedIndex())); params.setClearROIS(checkDelROIs.isSelected()); params.setSaveImages(checkImage.isSelected()); params.setSaveResults(checkResults.isSelected()); From b7ae3aa07c69b2d19e7d52ac22942956a79435a5 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Sun, 5 Nov 2023 13:13:49 +0100 Subject: [PATCH 28/33] Fix ROI manager usage in loops --- src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index 223d622..0b25e98 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -498,11 +498,11 @@ private void runMacro() { String property = ROIWrapper.IJ_PROPERTY; WindowManager.closeAllWindows(); - // Initialize ROI Manager - initRoiManager(); - int index = 0; for (BatchImage image : images) { + // Initialize ROI Manager + initRoiManager(); + //noinspection HardcodedFileSeparator setProgress("Image " + (index + 1) + "/" + images.size()); setState("Opening image..."); From 1aadf3fb70e200eca7f79207cb2ebb6573950244 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Mon, 6 Nov 2023 01:03:12 +0100 Subject: [PATCH 29/33] Load local ROI files stored alongside the image file --- .../java/fr/igred/ij/io/LocalBatchImage.java | 74 +++++++++++++++++++ .../java/fr/igred/ij/io/OMEROBatchImage.java | 18 ++++- 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/igred/ij/io/LocalBatchImage.java b/src/main/java/fr/igred/ij/io/LocalBatchImage.java index f6e8b26..870eacb 100644 --- a/src/main/java/fr/igred/ij/io/LocalBatchImage.java +++ b/src/main/java/fr/igred/ij/io/LocalBatchImage.java @@ -19,6 +19,9 @@ import fr.igred.omero.repository.ImageWrapper; import ij.ImagePlus; +import ij.gui.Overlay; +import ij.gui.Roi; +import ij.plugin.frame.RoiManager; import loci.formats.FileStitcher; import loci.formats.FormatException; import loci.plugins.BF; @@ -32,6 +35,7 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.logging.Logger; @@ -179,6 +183,7 @@ public ImagePlus getImagePlus(ROIMode mode) { options.setShowROIs(loadROIs); if (loadROIs) { options.setROIsMode(mode.toString()); + loadROIs(imp, RoiManager.getInstance2(), mode); } options.setId(path); options.setSeriesOn(index, true); @@ -190,4 +195,73 @@ public ImagePlus getImagePlus(ROIMode mode) { return imp; } + + /** + * Returns the path to the ROI next to the image file. + * + * @return See above. + */ + @SuppressWarnings("MagicCharacter") + private String getRoiPath() { + String beforeExt = path.substring(0, path.lastIndexOf('.')); + beforeExt = beforeExt.isEmpty() ? path : beforeExt; + if (beforeExt.toLowerCase(Locale.ROOT).endsWith(".ome") && beforeExt.lastIndexOf('.') > 0) { + beforeExt = beforeExt.substring(0, beforeExt.lastIndexOf('.')); + } + + String imageIndex = index == null || index.equals(0) ? "" : "-" + index; + + boolean roiExists; + String roiPath = beforeExt + imageIndex + ".roi"; + File roiFile = new File(roiPath); + if (!roiFile.exists() || !roiFile.isFile()) { + roiPath = beforeExt + imageIndex + "_RoiSet.zip"; + File zipFile = new File(roiPath); + roiExists = zipFile.exists() && zipFile.isFile(); + } else { + roiExists = true; + } + return roiExists ? roiPath : ""; + } + + + /** + * Loads ROIs from an image in OMERO into ImageJ. + * + * @param imp The image in ImageJ ROIs should be linked to. + * @param manager The ROI Manager. + * @param roiMode The mode used to load ROIs. + */ + private void loadROIs(ImagePlus imp, RoiManager manager, ROIMode roiMode) { + RoiManager rm = manager; + if (rm == null) { + rm = RoiManager.getRoiManager(); + } + + String roiPath = getRoiPath(); + if (!roiPath.isEmpty() && roiMode != ROIMode.DO_NOT_LOAD) { + rm.open(roiPath); + Roi[] ijRois = rm.getRoisAsArray(); + for (Roi ijRoi : ijRois) { + ijRoi.setImage(imp); + } + if (imp != null && roiMode == ROIMode.OVERLAY) { + Overlay overlay = imp.getOverlay(); + for (Roi ijRoi : ijRois) { + overlay.add(ijRoi, ijRoi.getName()); + } + rm.reset(); + } + } + } + + + @Override + public String toString() { + return "LocalBatchImage{" + + "path='" + path + "'" + + ", index=" + index + + "}"; + } + } diff --git a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java index 7adfdfc..e03ef0e 100644 --- a/src/main/java/fr/igred/ij/io/OMEROBatchImage.java +++ b/src/main/java/fr/igred/ij/io/OMEROBatchImage.java @@ -99,7 +99,7 @@ public ImagePlus getImagePlus(ROIMode mode) { // Store image "annotate" permissions as a property in the ImagePlus object imp.setProp("Annotatable", String.valueOf(imageWrapper.canAnnotate())); if (mode != ROIMode.DO_NOT_LOAD) { - loadROIs(imp, mode); + loadROIs(imp, RoiManager.getInstance2(), mode); } } catch (ExecutionException | ServiceException | AccessException e) { LOGGER.severe("Could not load image: " + e.getMessage()); @@ -109,14 +109,15 @@ public ImagePlus getImagePlus(ROIMode mode) { /** - * Loads ROIs from an image in OMERO into ImageJ. + * Loads ROIs from an image in OMERO into ImageJ (removes previous ROIs). * * @param imp The image in ImageJ ROIs should be linked to. + * @param manager The ROI Manager. * @param roiMode The mode used to load ROIs. */ - private void loadROIs(ImagePlus imp, ROIMode roiMode) { + private void loadROIs(ImagePlus imp, RoiManager manager, ROIMode roiMode) { List ijRois = new ArrayList<>(0); - RoiManager rm = RoiManager.getInstance2(); + RoiManager rm = manager; if (rm == null) { rm = RoiManager.getRoiManager(); } @@ -145,4 +146,13 @@ private void loadROIs(ImagePlus imp, ROIMode roiMode) { } } + + @Override + public String toString() { + return "OMEROBatchImage{" + + "client=" + client + + ", imageWrapper=" + imageWrapper + + "}"; + } + } From 6415639f902cac16ba427d0861cab08dac05305f Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Mon, 6 Nov 2023 02:28:29 +0100 Subject: [PATCH 30/33] Fix dataset label not hiding and rename variables --- .../ij/plugin/frame/OMEROBatchPlugin.java | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java index 3def198..f132f61 100644 --- a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java +++ b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java @@ -98,7 +98,6 @@ public class OMEROBatchPlugin extends PlugInFrame implements BatchListener { // choices of input images private final JPanel input1a = new JPanel(); private final JPanel input1b = new JPanel(); - private final JPanel input3 = new JPanel(); private final JPanel input2 = new JPanel(); // group and user selection @@ -147,14 +146,10 @@ public class OMEROBatchPlugin extends PlugInFrame implements BatchListener { /** The checkbox to save locally. */ private final JCheckBox localOutput = new JCheckBox("Local"); - // existing dataset - private final JPanel output3a = new JPanel(); /** The list of possible output projects. */ private final JComboBox projectListOut = new JComboBox<>(); /** The list of possible output datasets. */ private final JComboBox datasetListOut = new JComboBox<>(); - /** The button to create a new dataset. */ - private final JButton newDatasetBtn = new JButton("New"); // local private final JPanel output3b = new JPanel(); @@ -202,8 +197,8 @@ public OMEROBatchPlugin() { super("OMERO Batch Plugin"); super.setMinimumSize(minimumSize); - final String projectName = "Project Name: "; - final String datasetName = "Dataset Name: "; + final String projectName = "Project: "; + final String datasetName = "Dataset: "; final String browse = "Browse"; final Font nameFont = new Font("Arial", Font.ITALIC, 10); @@ -255,8 +250,8 @@ public OMEROBatchPlugin() { source.setBorder(BorderFactory.createTitledBorder("Source")); super.add(source); - JLabel labelGroup = new JLabel("Group Name: "); - JLabel labelUser = new JLabel("User Name: "); + JLabel labelGroup = new JLabel("Group: "); + JLabel labelUser = new JLabel("User: "); labelGroup.setLabelFor(groupList); labelUser.setLabelFor(userList); input1a.add(labelGroup); @@ -298,7 +293,9 @@ public OMEROBatchPlugin() { input2.add(recursive); inputFolderBtn.addActionListener(e -> chooseDirectory(inputFolder)); + JPanel input3 = new JPanel(); JLabel labelROIMode = new JLabel("Load ROIs: "); + labelROIMode.setLabelFor(roiMode); input3.add(labelROIMode); input3.add(roiMode); input3.add(checkDelROIs); @@ -378,17 +375,20 @@ public OMEROBatchPlugin() { output2.add(labelExtension); output2.add(suffix); + JPanel output3a = new JPanel(); + JPanel output3a1 = new JPanel(); + JButton newDatasetBtn = new JButton("New"); JLabel labelProjectOut = new JLabel(projectName); JLabel labelDatasetOut = new JLabel(datasetName); labelProjectOut.setLabelFor(projectListOut); labelDatasetOut.setLabelFor(datasetListOut); output3a.add(labelProjectOut); output3a.add(projectListOut); - output3a.add(Box.createRigidArea(smallHorizontal)); - output3a.add(labelDatasetOut); - output3a.add(datasetListOut); - output3a.add(Box.createRigidArea(smallHorizontal)); - output3a.add(newDatasetBtn); + output3a1.add(labelDatasetOut); + output3a1.add(datasetListOut); + output3a1.add(Box.createRigidArea(smallHorizontal)); + output3a1.add(newDatasetBtn); + output3a.add(output3a1); projectListOut.addItemListener(this::updateOutputProject); datasetListOut.addItemListener(this::updateOutputDataset); newDatasetBtn.addActionListener(this::createNewDataset); @@ -407,8 +407,8 @@ public OMEROBatchPlugin() { // choice of output JPanel panelOutput = new JPanel(); - panelOutput.add(output2); panelOutput.add(output1); + panelOutput.add(output2); panelOutput.add(output3a); panelOutput.add(output3b); panelOutput.setLayout(new BoxLayout(panelOutput, BoxLayout.PAGE_AXIS)); @@ -567,7 +567,7 @@ public void run(String arg) { * @param username The OMERO user. * @param userId The user ID. */ - public void userProjectsAndDatasets(String username, long userId) { + private void userProjects(String username, long userId) { if ("All members".equals(username)) { userProjects = groupProjects; } else { @@ -719,7 +719,7 @@ private void updateUser(ItemEvent e) { if (index >= 1) { userId = users.get(index - 1).getId(); } - userProjectsAndDatasets(username, userId); + userProjects(username, userId); projectListIn.removeAllItems(); projectListOut.removeAllItems(); datasetListIn.removeAllItems(); @@ -994,9 +994,9 @@ public void start(ActionEvent e) { BatchParameters params = new BatchParameters(); // initialization of success variables - boolean checkInput; - boolean checkMacro = getMacro(); - boolean checkOutput = getOutput(); + boolean badInput; + boolean badMacro = !getMacro(); + boolean badOutput = !getOutput(); // input data params.setSuffix(suffix.getText()); @@ -1016,9 +1016,9 @@ public void start(ActionEvent e) { inputDatasetId = dataset.getId(); List imageWrappers = dataset.getImages(client); images = listImages(client, imageWrappers); - checkInput = true; + badInput = false; } else { // local.isSelected() - checkInput = getLocalInput(); + badInput = !getLocalInput(); images = listImages(directoryIn, recursive.isSelected()); } params.setOutputDatasetId(inputDatasetId); @@ -1027,7 +1027,7 @@ public void start(ActionEvent e) { return; } - if (!checkInput || !checkMacro || !checkOutput) { + if (badInput || badMacro || badOutput) { return; } @@ -1073,9 +1073,8 @@ private void updateOutput(ActionEvent e) { } output2.setVisible(outputImage); - output3a.setVisible(outputOnline && (outputImage || outputResults)); - datasetListOut.setVisible(outputOnline && outputImage); - newDatasetBtn.setVisible(outputOnline && outputImage); + projectListOut.getParent().setVisible(outputOnline && (outputImage || outputResults)); + datasetListOut.getParent().setVisible(outputOnline && outputImage); if (outputOnline && userProjects.equals(myProjects)) { projectListOut.setSelectedIndex(projectListIn.getSelectedIndex()); } From d4fae80e7f6669b83de9f5821e00987a252399e0 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Mon, 6 Nov 2023 02:43:15 +0100 Subject: [PATCH 31/33] Remove JPanel fields from Plugin (use getParent() instead) --- .../ij/plugin/frame/OMEROBatchPlugin.java | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java index f132f61..5a7737f 100644 --- a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java +++ b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java @@ -95,11 +95,6 @@ public class OMEROBatchPlugin extends PlugInFrame implements BatchListener { /** The local input button. */ private final JRadioButton local = new JRadioButton("Local"); - // choices of input images - private final JPanel input1a = new JPanel(); - private final JPanel input1b = new JPanel(); - private final JPanel input2 = new JPanel(); - // group and user selection /** The list of groups. */ private final JComboBox groupList = new JComboBox<>(); @@ -136,7 +131,6 @@ public class OMEROBatchPlugin extends PlugInFrame implements BatchListener { /** The checkbox to save the log. */ private final JCheckBox checkLog = new JCheckBox("Log file"); - private final JPanel output2 = new JPanel(); /** The suffix of the output files. */ private final JTextField suffix = new JTextField(10); @@ -151,8 +145,6 @@ public class OMEROBatchPlugin extends PlugInFrame implements BatchListener { /** The list of possible output datasets. */ private final JComboBox datasetListOut = new JComboBox<>(); - // local - private final JPanel output3b = new JPanel(); /** The output folder. */ private final JTextField outputFolder = new JTextField(20); @@ -250,6 +242,7 @@ public OMEROBatchPlugin() { source.setBorder(BorderFactory.createTitledBorder("Source")); super.add(source); + JPanel input1a = new JPanel(); JLabel labelGroup = new JLabel("Group: "); JLabel labelUser = new JLabel("User: "); labelGroup.setLabelFor(groupList); @@ -264,6 +257,7 @@ public OMEROBatchPlugin() { groupList.setFont(listFont); userList.setFont(listFont); + JPanel input1b = new JPanel(); JLabel labelProjectIn = new JLabel(projectName); JLabel labelDatasetIn = new JLabel(datasetName); JButton preview = new JButton("Preview"); @@ -282,6 +276,7 @@ public OMEROBatchPlugin() { projectListIn.setFont(listFont); datasetListIn.setFont(listFont); + JPanel input2 = new JPanel(); JLabel inputFolderLabel = new JLabel("Images folder: "); JButton inputFolderBtn = new JButton(browse); inputFolderLabel.setLabelFor(inputFolder); @@ -369,6 +364,7 @@ public OMEROBatchPlugin() { onlineOutput.addActionListener(this::updateOutput); localOutput.addActionListener(this::updateOutput); + JPanel output2 = new JPanel(); JLabel labelExtension = new JLabel("Suffix of output files:"); labelExtension.setLabelFor(suffix); suffix.setText("_macro"); @@ -395,6 +391,7 @@ public OMEROBatchPlugin() { projectListOut.setFont(listFont); datasetListOut.setFont(listFont); + JPanel output3b = new JPanel(); JLabel outputFolderLabel = new JLabel("Output folder: "); JButton directoryBtn = new JButton(browse); outputFolderLabel.setLabelFor(outputFolder); @@ -800,19 +797,19 @@ private void updateInput(ItemEvent e) { connected = connect(); } if (connected) { - input1a.setVisible(true); - input1b.setVisible(true); - input2.setVisible(false); + groupList.getParent().setVisible(true); + projectListIn.getParent().setVisible(true); + inputFolder.getParent().setVisible(false); checkDelROIs.setVisible(true); } else { local.setSelected(true); } } else { //local.isSelected() - input2.setVisible(true); + inputFolder.getParent().setVisible(true); checkDelROIs.setSelected(false); checkDelROIs.setVisible(false); - input1b.setVisible(false); - input1a.setVisible(false); + projectListIn.getParent().setVisible(false); + groupList.getParent().setVisible(false); } this.repack(); } @@ -1072,13 +1069,13 @@ private void updateOutput(ActionEvent e) { onlineOutput.setSelected(outputOnline); } - output2.setVisible(outputImage); + suffix.getParent().setVisible(outputImage); projectListOut.getParent().setVisible(outputOnline && (outputImage || outputResults)); datasetListOut.getParent().setVisible(outputOnline && outputImage); if (outputOnline && userProjects.equals(myProjects)) { projectListOut.setSelectedIndex(projectListIn.getSelectedIndex()); } - output3b.setVisible(outputLocal); + outputFolder.getParent().setVisible(outputLocal); repack(); } @@ -1265,12 +1262,12 @@ private void repack() { this.pack(); this.setMinimumSize(bestSize); - Container inputPanel = input1b.getParent(); + Container inputPanel = projectListIn.getParent().getParent(); inputPanel.setMinimumSize(inputPanel.getPreferredSize()); inputPanel.setMaximumSize( new Dimension(inputPanel.getMaximumSize().width, inputPanel.getPreferredSize().height)); - Container outputPanel = output2.getParent(); + Container outputPanel = onlineOutput.getParent().getParent(); outputPanel.setMinimumSize(outputPanel.getPreferredSize()); outputPanel.setMaximumSize(new Dimension(outputPanel.getMaximumSize().width, outputPanel.getHeight())); } From 97b67fbf60c6626cd6063b3a965a0ee7e6e3dca2 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Mon, 6 Nov 2023 03:01:07 +0100 Subject: [PATCH 32/33] Allow to "clear ROIs" (=overwrite) when saving locally --- src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java | 6 ++++-- .../java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java | 7 ++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java index 0b25e98..19c1ad6 100644 --- a/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java +++ b/src/main/java/fr/igred/ij/macro/OMEROBatchRunner.java @@ -669,8 +669,9 @@ private List saveImage(ImagePlus image, String property) { private void saveOverlay(ImagePlus imp, Long imageId, String title, String property) { if (params.isOutputOnLocal()) { // local save setState("Saving overlay ROIs..."); + String timestamp = params.shouldClearROIs() ? "" : timestamp() + "_"; String path = params.getDirectoryOut() + File.separator + - title + "_" + timestamp() + "_RoiSet.zip"; + title + "_" + timestamp + "RoiSet.zip"; List ijRois = getOverlay(imp); saveRoiFile(ijRois, path); } @@ -702,8 +703,9 @@ private void saveOverlay(ImagePlus imp, Long imageId, String title, String prope private void saveROIManager(ImagePlus imp, Long imageId, String title, String property) { if (params.isOutputOnLocal()) { // local save setState("Saving ROIs..."); + String timestamp = params.shouldClearROIs() ? "" : timestamp() + "_"; String path = params.getDirectoryOut() + File.separator + - title + "_" + timestamp() + "_RoiSet.zip"; + title + "_" + timestamp + "RoiSet.zip"; List ijRois = getManagedRois(imp); saveRoiFile(ijRois, path); } diff --git a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java index 5a7737f..ed111c1 100644 --- a/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java +++ b/src/main/java/fr/igred/ij/plugin/frame/OMEROBatchPlugin.java @@ -800,14 +800,11 @@ private void updateInput(ItemEvent e) { groupList.getParent().setVisible(true); projectListIn.getParent().setVisible(true); inputFolder.getParent().setVisible(false); - checkDelROIs.setVisible(true); } else { local.setSelected(true); } } else { //local.isSelected() inputFolder.getParent().setVisible(true); - checkDelROIs.setSelected(false); - checkDelROIs.setVisible(false); projectListIn.getParent().setVisible(false); groupList.getParent().setVisible(false); } @@ -1185,8 +1182,8 @@ private boolean getLocalOutput() { */ private boolean checkDeleteROIs() { boolean check = true; - if (checkDelROIs.isSelected() && (!onlineOutput.isSelected() || !checkROIs.isSelected())) { - errorWindow(String.format("ROIs:%nYou can't clear ROIs if you don't save ROIs on OMERO")); + if (checkDelROIs.isSelected() && !checkROIs.isSelected()) { + errorWindow(String.format("ROIs:%nYou can't clear ROIs if you don't save ROIs")); check = false; } return check; From 14365f305a4d1a0976fce5b2a2c4e96a56d88821 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Mon, 6 Nov 2023 03:04:08 +0100 Subject: [PATCH 33/33] Bump pom-scijava version and update info --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index aa6dfe8..04485a7 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ pom-scijava org.scijava - 36.0.0 + 37.0.0 fr.igred @@ -48,7 +48,7 @@ ppouchin Pierre Pouchin pierre.pouchin@uca.fr - https://www.igred.fr/directory/member/pierre-pouchin/ + https://www.igred.fr/en/member/pierre_pouchin/ GReD (INSERM U1103 / CNRS UMR 6293 / UCA) https://www.igred.fr