Search in sources :

Example 1 with CompressionType

use of qupath.lib.images.writers.ome.OMEPyramidWriter.CompressionType in project qupath by qupath.

the class ConvertCommand method run.

@Override
public void run() {
    long startTime = System.currentTimeMillis();
    try {
        if (inputFile == null || outputFile == null)
            throw new IOException("Incorrect given path(s)");
    } catch (IOException e) {
        logger.error(e.getLocalizedMessage());
        return;
    }
    // Change name if not ending with .ome.tif
    if (!outputFile.getAbsolutePath().toLowerCase().endsWith(".ome.tif"))
        outputFile = new File(outputFile.getParentFile(), GeneralTools.getNameWithoutExtension(outputFile) + ".ome.tif");
    if (outputFile.exists() && !overwrite) {
        logger.error("Output file " + outputFile + " exists!");
        return;
    }
    if (inputFile.equals(outputFile)) {
        logger.error("Input and output files are the same!");
        return;
    }
    String[] args;
    if (series >= 0)
        args = new String[] { "--classname", BioFormatsServerBuilder.class.getName(), "--series", Integer.toString(series) };
    else
        args = new String[0];
    createTileCache();
    try (ImageServer<BufferedImage> server = ImageServers.buildServer(inputFile.toURI(), args)) {
        // Get compression from user (or CompressionType.DEFAULT)
        // CompressionType compressionType = stringToCompressionType(compression);
        CompressionType compressionType = compression;
        // Check that compression is compatible with image
        if (!Arrays.stream(CompressionType.values()).filter(c -> c.supportsImage(server)).anyMatch(c -> c == compressionType)) {
            logger.error("Chosen compression " + compressionType.toString() + " is not compatible with the input image.");
        }
        if (tileSize > -1) {
            tileWidth = tileSize;
            tileHeight = tileSize;
        }
        Builder builder = new OMEPyramidWriter.Builder(server).compression(compressionType).tileSize(tileWidth, tileHeight).parallelize(parallelize);
        if (bigTiff != null)
            builder = builder.bigTiff(bigTiff.booleanValue());
        // Make pyramidal, if requested
        if (downsample < 1)
            downsample = server.getDownsampleForResolution(0);
        if (pyramid > 1)
            builder.scaledDownsampling(downsample, pyramid);
        else
            builder.downsamples(downsample);
        String patternRange = "(\\d+)-(\\d+)";
        String patternInteger = "\\d+";
        // Parse z-slices, remembering to convert from 1-based (inclusive) to 0-based (upper value exclusive) indexing
        if (zSlices == null || zSlices.isBlank() || "all".equals(zSlices)) {
            builder.allZSlices();
        } else if (zSlices.matches(patternRange)) {
            int zStart = Integer.parseInt(zSlices.substring(0, zSlices.indexOf("-")));
            int zEnd = Integer.parseInt(zSlices.substring(zSlices.indexOf("-") + 1));
            if (zEnd == zStart)
                builder.zSlice(zStart - 1);
            else if (zStart > zEnd) {
                logger.error("Invalid range of --zslices (must be ascending): " + zSlices);
                return;
            } else
                builder.zSlices(zStart - 1, zEnd);
        } else if (zSlices.matches(patternInteger)) {
            int z = Integer.parseInt(zSlices);
            builder.zSlice(z - 1);
        } else {
            logger.error("Unknown value for --zslices: " + zSlices);
            return;
        }
        // Parse timepoints, remembering to convert from 1-based (inclusive) to 0-based (upper value exclusive) indexing
        if ("all".equals(timepoints)) {
            builder.allTimePoints();
        } else if (timepoints.matches(patternRange)) {
            int tStart = Integer.parseInt(timepoints.substring(0, timepoints.indexOf("-")));
            int tEnd = Integer.parseInt(timepoints.substring(timepoints.indexOf("-") + 1));
            if (tStart == tEnd)
                builder.timePoint(tStart - 1);
            else if (tStart > tEnd) {
                logger.error("Invalid range of --timepoints (must be ascending): " + timepoints);
                return;
            } else
                builder.timePoints(tStart - 1, tEnd);
        } else if (timepoints.matches(patternInteger)) {
            int t = Integer.parseInt(timepoints);
            builder.timePoint(t - 1);
        } else {
            logger.error("Unknown value for --timepoints: " + timepoints);
            return;
        }
        // Parse the bounding box, if required
        if (crop != null && !crop.isBlank()) {
            var matcher = Pattern.compile("(\\d+),(\\d+),(\\d+),(\\d+)").matcher(crop);
            if (matcher.matches()) {
                int x = Integer.parseInt(matcher.group(1));
                int y = Integer.parseInt(matcher.group(2));
                int w = Integer.parseInt(matcher.group(3));
                int h = Integer.parseInt(matcher.group(4));
                builder.region(x, y, w, h);
            } else {
                logger.error("Unknown value for --crop: " + crop);
                return;
            }
        }
        builder.build().writeSeries(outputFile.getPath());
        long duration = System.currentTimeMillis() - startTime;
        logger.info(String.format("%s written in %.1f seconds", outputFile.getAbsolutePath(), duration / 1000.0));
    } catch (Exception e) {
        logger.error(e.getLocalizedMessage(), e);
    }
}
Also used : Arrays(java.util.Arrays) ImageServer(qupath.lib.images.servers.ImageServer) Logger(org.slf4j.Logger) Builder(qupath.lib.images.writers.ome.OMEPyramidWriter.Builder) BufferedImage(java.awt.image.BufferedImage) Parameters(picocli.CommandLine.Parameters) GeneralTools(qupath.lib.common.GeneralTools) Subcommand(qupath.lib.gui.extensions.Subcommand) ImageServerProvider(qupath.lib.images.servers.ImageServerProvider) LoggerFactory(org.slf4j.LoggerFactory) IOException(java.io.IOException) BioFormatsServerBuilder(qupath.lib.images.servers.bioformats.BioFormatsServerBuilder) File(java.io.File) Option(picocli.CommandLine.Option) ImageRegionStoreFactory(qupath.lib.gui.images.stores.ImageRegionStoreFactory) Pattern(java.util.regex.Pattern) Command(picocli.CommandLine.Command) ImageServers(qupath.lib.images.servers.ImageServers) CompressionType(qupath.lib.images.writers.ome.OMEPyramidWriter.CompressionType) PathPrefs(qupath.lib.gui.prefs.PathPrefs) Builder(qupath.lib.images.writers.ome.OMEPyramidWriter.Builder) BioFormatsServerBuilder(qupath.lib.images.servers.bioformats.BioFormatsServerBuilder) IOException(java.io.IOException) BufferedImage(java.awt.image.BufferedImage) IOException(java.io.IOException) Builder(qupath.lib.images.writers.ome.OMEPyramidWriter.Builder) File(java.io.File) CompressionType(qupath.lib.images.writers.ome.OMEPyramidWriter.CompressionType)

Example 2 with CompressionType

use of qupath.lib.images.writers.ome.OMEPyramidWriter.CompressionType in project qupath by qupath.

the class OMEPyramidWriterCommand method run.

@Override
public void run() {
    if (currentTask != null && !currentTask.isDone()) {
        if (!Dialogs.showConfirmDialog("OME Pyramid writer", "Do you want to stop the current export?"))
            // TODO: Delete exporting file?
            return;
        else {
            currentTask.cancel(true);
        }
    }
    QuPathViewer viewer = qupath.getViewer();
    int zPos = viewer.getZPosition();
    int tPos = viewer.getTPosition();
    ImageData<BufferedImage> imageData = viewer.getImageData();
    if (imageData == null) {
        Dialogs.showNoImageError("OME Pyramid writer");
        return;
    }
    ImageServer<BufferedImage> server = imageData.getServer();
    // Region
    PathObject selected = imageData.getHierarchy().getSelectionModel().getSelectedObject();
    ImageRegion region = null;
    int width, height;
    if (selected == null || !selected.hasROI() || !selected.getROI().isArea()) {
        width = server.getWidth();
        height = server.getHeight();
    } else {
        region = ImageRegion.createInstance(selected.getROI());
        width = region.getWidth();
        height = region.getHeight();
    }
    // Set compression - with a sanity check for validity, defaulting to another comparable method if necessary
    CompressionType compression = getDefaultPyramidCompression();
    List<String> compatibleCompression = Arrays.stream(CompressionType.values()).filter(c -> c.supportsImage(server)).map(c -> c.toFriendlyString()).collect(Collectors.toList());
    if (!compatibleCompression.contains(compression.toFriendlyString()))
        compression = CompressionType.DEFAULT;
    var params = new ParameterList().addChoiceParameter("compression", "Compression type", compression.toFriendlyString(), compatibleCompression).addIntParameter("scaledDownsample", "Pyramidal downsample", scaledDownsample.get(), "", 1, 8, "Amount to downsample each consecutive pyramidal level; use 1 to indicate the image should not be pyramidal").addIntParameter("tileSize", "Tile size", getDefaultTileSize(), "px", "Tile size for export (should be between 128 and 8192)").addBooleanParameter("parallelize", "Parallelize export", parallelizeTiling.get(), "Export image tiles in parallel - " + "this should be faster, best keep it on unless you encounter export problems").addBooleanParameter("allZ", "All z-slices", allZ.get(), "Include all z-slices in the stack").addBooleanParameter("allT", "All timepoints", allT.get(), "Include all timepoints in the time-series");
    boolean singleTile = server.getTileRequestManager().getTileRequests(RegionRequest.createInstance(server)).size() == 1;
    params.setHiddenParameters(server.nZSlices() == 1, "allZ");
    params.setHiddenParameters(server.nTimepoints() == 1, "allT");
    params.setHiddenParameters(singleTile, "tileSize", "parallelize");
    if (!Dialogs.showParameterDialog("Export OME-TIFF", params))
        return;
    compression = CompressionType.fromFriendlyString((String) params.getChoiceParameterValue("compression"));
    defaultPyramidCompression.set(compression);
    int downsampleScale = params.getIntParameterValue("scaledDownsample");
    scaledDownsample.set(downsampleScale);
    int tileSize = params.getIntParameterValue("tileSize");
    boolean parallelize = params.getBooleanParameterValue("parallelize");
    if (!singleTile) {
        tileSize = GeneralTools.clipValue(tileSize, 128, 8192);
        defaultTileSize.set(tileSize);
        parallelizeTiling.set(parallelize);
    }
    boolean doAllZ = false;
    boolean doAllT = false;
    if (server.nZSlices() > 1) {
        doAllZ = params.getBooleanParameterValue("allZ");
        allZ.set(doAllZ);
    }
    if (server.nTimepoints() > 1) {
        doAllT = params.getBooleanParameterValue("allT");
        allT.set(doAllT);
    }
    OMEPyramidWriter.Builder builder = new OMEPyramidWriter.Builder(server);
    if (region != null) {
        builder = builder.region(region);
    } else {
        if (server.nZSlices() > 1 && !doAllZ)
            builder.zSlice(zPos);
        if (server.nTimepoints() > 1 && !doAllT)
            builder.timePoint(tPos);
    }
    builder.compression(compression);
    if (downsampleScale <= 1 || Math.max(width, height) / server.getDownsampleForResolution(0) < minSizeForTiling.get())
        builder.downsamples(server.getDownsampleForResolution(0));
    else
        builder.scaledDownsampling(server.getDownsampleForResolution(0), downsampleScale);
    // Set tile size; if we just have one tile, use the image width & height
    if (singleTile)
        builder = builder.tileSize(width, height);
    else
        builder = builder.tileSize(tileSize).parallelize(parallelize);
    if (server.nZSlices() > 1 && doAllZ)
        builder.allZSlices();
    if (server.nTimepoints() > 1 && doAllT)
        builder.allTimePoints();
    // Prompt for file
    File fileOutput = Dialogs.promptToSaveFile("Write pyramid", null, null, "OME TIFF pyramid", ".ome.tif");
    if (fileOutput == null)
        return;
    String name = fileOutput.getName();
    // We can have trouble with only the '.tif' part of the name being included
    if (name.endsWith(".tif") && !name.endsWith(".ome.tif"))
        fileOutput = new File(fileOutput.getParentFile(), name.substring(0, name.length() - 4) + ".ome.tif");
    OMEPyramidSeries writer = builder.build();
    if (pool == null) {
        pool = Executors.newSingleThreadExecutor(ThreadTools.createThreadFactory("ome-pyramid-export", false));
    }
    currentTask = pool.submit(new WriterTask(OMEPyramidWriter.createWriter(writer), fileOutput.getAbsolutePath()));
}
Also used : Arrays(java.util.Arrays) ImageServer(qupath.lib.images.servers.ImageServer) LoggerFactory(org.slf4j.LoggerFactory) IntegerProperty(javafx.beans.property.IntegerProperty) Dialogs(qupath.lib.gui.dialogs.Dialogs) Future(java.util.concurrent.Future) ParameterList(qupath.lib.plugins.parameters.ParameterList) OMEPyramidSeries(qupath.lib.images.writers.ome.OMEPyramidWriter.OMEPyramidSeries) ImageRegion(qupath.lib.regions.ImageRegion) CompressionType(qupath.lib.images.writers.ome.OMEPyramidWriter.CompressionType) ExecutorService(java.util.concurrent.ExecutorService) QuPathGUI(qupath.lib.gui.QuPathGUI) ImageData(qupath.lib.images.ImageData) ObjectProperty(javafx.beans.property.ObjectProperty) Logger(org.slf4j.Logger) BufferedImage(java.awt.image.BufferedImage) GeneralTools(qupath.lib.common.GeneralTools) RegionRequest(qupath.lib.regions.RegionRequest) Collectors(java.util.stream.Collectors) File(java.io.File) Executors(java.util.concurrent.Executors) PathObject(qupath.lib.objects.PathObject) ClosedByInterruptException(java.nio.channels.ClosedByInterruptException) QuPathViewer(qupath.lib.gui.viewer.QuPathViewer) List(java.util.List) BooleanProperty(javafx.beans.property.BooleanProperty) ThreadTools(qupath.lib.common.ThreadTools) PathPrefs(qupath.lib.gui.prefs.PathPrefs) ImageRegion(qupath.lib.regions.ImageRegion) BufferedImage(java.awt.image.BufferedImage) PathObject(qupath.lib.objects.PathObject) OMEPyramidSeries(qupath.lib.images.writers.ome.OMEPyramidWriter.OMEPyramidSeries) ParameterList(qupath.lib.plugins.parameters.ParameterList) CompressionType(qupath.lib.images.writers.ome.OMEPyramidWriter.CompressionType) File(java.io.File) QuPathViewer(qupath.lib.gui.viewer.QuPathViewer)

Aggregations

BufferedImage (java.awt.image.BufferedImage)2 File (java.io.File)2 Arrays (java.util.Arrays)2 Logger (org.slf4j.Logger)2 LoggerFactory (org.slf4j.LoggerFactory)2 GeneralTools (qupath.lib.common.GeneralTools)2 PathPrefs (qupath.lib.gui.prefs.PathPrefs)2 ImageServer (qupath.lib.images.servers.ImageServer)2 CompressionType (qupath.lib.images.writers.ome.OMEPyramidWriter.CompressionType)2 IOException (java.io.IOException)1 ClosedByInterruptException (java.nio.channels.ClosedByInterruptException)1 List (java.util.List)1 ExecutorService (java.util.concurrent.ExecutorService)1 Executors (java.util.concurrent.Executors)1 Future (java.util.concurrent.Future)1 Pattern (java.util.regex.Pattern)1 Collectors (java.util.stream.Collectors)1 BooleanProperty (javafx.beans.property.BooleanProperty)1 IntegerProperty (javafx.beans.property.IntegerProperty)1 ObjectProperty (javafx.beans.property.ObjectProperty)1