Search in sources :

Example 76 with Layer

use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.

the class Loader method importImage.

/**
 * Import a new image at the given coordinates; does not puts it into any layer, unless it's a stack -in which case importStack is called with the current front layer of the given project as target. If a path is not provided it will be asked for.
 */
public Patch importImage(final Project project, final double x, final double y, String path, final boolean synch_mipmap_generation) {
    if (null == path) {
        final OpenDialog od = new OpenDialog("Import image", "");
        final String name = od.getFileName();
        if (null == name || 0 == name.length())
            return null;
        String dir = od.getDirectory().replace('\\', '/');
        if (!dir.endsWith("/"))
            dir += "/";
        path = dir + name;
    } else {
        path = path.replace('\\', '/');
    }
    // avoid opening trakem2 projects
    if (path.toLowerCase().endsWith(".xml")) {
        Utils.showMessage("Cannot import " + path + " as a stack.");
        return null;
    }
    releaseToFit(new File(path).length() * 3);
    IJ.redirectErrorMessages();
    final ImagePlus imp = openImagePlus(path);
    if (null == imp)
        return null;
    if (imp.getNSlices() > 1) {
        // a stack!
        final Layer layer = Display.getFrontLayer(project);
        if (null == layer)
            return null;
        importStack(layer, x, y, imp, true, path, true);
        return null;
    }
    if (0 == imp.getWidth() || 0 == imp.getHeight()) {
        Utils.showMessage("Can't import image of zero width or height.");
        flush(imp);
        return null;
    }
    final Patch p = new Patch(project, imp.getTitle(), x, y, imp);
    addedPatchFrom(path, p);
    // WARNING may be altered concurrently
    last_opened_path = path;
    if (isMipMapsRegenerationEnabled()) {
        if (synch_mipmap_generation) {
            try {
                // wait
                regenerateMipMaps(p).get();
            } catch (final Exception e) {
                IJError.print(e);
            }
        } else
            // queue for regeneration
            regenerateMipMaps(p);
    }
    return p;
}
Also used : File(java.io.File) ImagePlus(ij.ImagePlus) Layer(ini.trakem2.display.Layer) Patch(ini.trakem2.display.Patch) IOException(java.io.IOException) FormatException(loci.formats.FormatException) OpenDialog(ij.io.OpenDialog)

Example 77 with Layer

use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.

the class Loader method importGrid.

/**
 * Import a grid of images and put them in the layer. If the directory (@param dir) is null, it'll be asked for.
 */
public Bureaucrat importGrid(final Layer layer, String dir) {
    try {
        String file = null;
        if (null == dir) {
            final String[] dn = Utils.selectFile("Select first image");
            if (null == dn)
                return null;
            dir = dn[0];
            file = dn[1];
        }
        // char digit digit
        String convention = "cdd";
        boolean chars_are_columns = true;
        // examine file name
        /*
		if (file.matches("\\A[a-zA-Z]\\d\\d.*")) { // one letter, 2 numbers
			//means:
			//	\A		- beggining of input
			//	[a-zA-Z]	- any letter upper or lower case
			//	\d\d		- two consecutive digits
			//	.*		- any row of chars
			ini_grid_convention = true;
		}
		*/
        // ask for chars->rows, numbers->columns or viceversa
        final GenericDialog gd = new GenericDialog("Conventions");
        gd.addStringField("file_name_contains:", "");
        gd.addNumericField("base_x: ", 0, 3);
        gd.addNumericField("base_y: ", 0, 3);
        gd.addMessage("Use: x(any), c(haracter), d(igit)");
        gd.addStringField("convention: ", convention);
        final String[] cr = new String[] { "columns", "rows" };
        gd.addChoice("characters are: ", cr, cr[0]);
        gd.addMessage("[File extension ignored]");
        // as asked by Joachim Walter
        gd.addNumericField("bottom-top overlap: ", 0, 3);
        gd.addNumericField("left-right overlap: ", 0, 3);
        gd.addCheckbox("link_images", false);
        gd.addCheckbox("montage with phase correlation", false);
        gd.addCheckbox("homogenize_contrast", true);
        final Component[] c = { (Component) gd.getSliders().get(gd.getSliders().size() - 2), (Component) gd.getNumericFields().get(gd.getNumericFields().size() - 2), (Component) gd.getSliders().get(gd.getSliders().size() - 1), (Component) gd.getNumericFields().get(gd.getNumericFields().size() - 1), (Component) gd.getChoices().get(gd.getChoices().size() - 1) };
        // enable the checkbox to control the slider and its associated numeric field:
        Utils.addEnablerListener((Checkbox) gd.getCheckboxes().get(gd.getCheckboxes().size() - 1), c, null);
        // gd.addCheckbox("Apply non-linear deformation", false);
        gd.showDialog();
        if (gd.wasCanceled()) {
            return null;
        }
        // collect data
        // filter away files not containing this tag
        final String regex = gd.getNextString();
        // the base x,y of the whole grid
        final double bx = gd.getNextNumber();
        final double by = gd.getNextNumber();
        // if (!ini_grid_convention) {
        convention = gd.getNextString().toLowerCase();
        // }
        if (/*!ini_grid_convention && */
        (null == convention || convention.equals("") || -1 == convention.indexOf('c') || -1 == convention.indexOf('d'))) {
            // TODO check that the convention has only 'cdx' chars and also that there is an island of 'c's and of 'd's only.
            Utils.showMessage("Convention '" + convention + "' needs both c(haracters) and d(igits), optionally 'x', and nothing else!");
            return null;
        }
        chars_are_columns = (0 == gd.getNextChoiceIndex());
        final double bt_overlap = gd.getNextNumber();
        final double lr_overlap = gd.getNextNumber();
        final boolean link_images = gd.getNextBoolean();
        final boolean stitch_tiles = gd.getNextBoolean();
        final boolean homogenize_contrast = gd.getNextBoolean();
        // start magic
        // get ImageJ-openable files that comply with the convention
        final File images_dir = new File(dir);
        if (!(images_dir.exists() && images_dir.isDirectory())) {
            Utils.showMessage("Something went wrong:\n\tCan't find directory " + dir);
            return null;
        }
        final String[] file_names = images_dir.list(new ImageFileFilter(regex, convention));
        if (null == file && file_names.length > 0) {
            // the 'selected' file
            file = file_names[0];
        }
        Utils.showStatus("Adding " + file_names.length + " patches.", false);
        if (0 == file_names.length) {
            Utils.log("Zero files match the convention '" + convention + "'");
            return null;
        }
        // How to: select all files, and order their names in a double array as they should be placed in the Display. Then place them, displacing by offset, and resizing if necessary.
        // gather image files:
        final Montage montage = new Montage(convention, chars_are_columns);
        montage.addAll(file_names);
        // an array of Object[] arrays, of unequal length maybe, each containing a column of image file names
        final ArrayList<String[]> cols = montage.getCols();
        // !@#$%^&*
        final String dir_ = dir;
        final double bt_overlap_ = bt_overlap;
        final double lr_overlap_ = lr_overlap;
        final String file_ = file;
        return Bureaucrat.createAndStart(new Worker.Task("Insert grid", true) {

            @Override
            public void exec() {
                StitchingTEM.PhaseCorrelationParam pc_param = null;
                if (stitch_tiles) {
                    pc_param = new StitchingTEM.PhaseCorrelationParam();
                    pc_param.setup(layer);
                }
                insertGrid(layer, dir_, file_, file_names.length, cols, bx, by, bt_overlap_, lr_overlap_, link_images, stitch_tiles, homogenize_contrast, pc_param, this);
            }
        }, layer.getProject());
    } catch (final Exception e) {
        IJError.print(e);
    }
    return null;
}
Also used : ImageFileFilter(ini.trakem2.io.ImageFileFilter) IOException(java.io.IOException) FormatException(loci.formats.FormatException) GenericDialog(ij.gui.GenericDialog) Montage(ini.trakem2.utils.Montage) Worker(ini.trakem2.utils.Worker) Component(java.awt.Component) File(java.io.File)

Example 78 with Layer

use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.

the class Loader method getFlatAWTImage.

/**
 * @param layer The layer from which to collect visible Displayable instances that intersect the srcRect.
 * @param srcRect_ Rectangle in World coordinates representing the field of view to paint into the image, and defines the width and height of the image together with the scale.
 * @param scale Value between 0 and 1.
 * @param c_alphas Which color channels to include when painting Patch instances that hold an RGB image.
 * @param type Either ImagePlus.GRAY8 or ImagePlus.COLOR_RGB
 * @param clazz Include only Displayable instances of this class; use Displayable.class for all.
 * @param al_displ List of Displayable instances to include. Use null to include all visible intersected by srcRect.
 * @param quality Whether to attempt to create a larger image and then scale it down with area averaging for best quality.
 * @param background The color of the areas of the image where no Displayable paints.
 * @param active Whether to paint a particular Displayable instance in an active state (as if it was selected in the UI).
 * @return
 */
public Image getFlatAWTImage(final Layer layer, final Rectangle srcRect_, final double scale, final int c_alphas, final int type, final Class<?> clazz, List<? extends Displayable> al_displ, boolean quality, final Color background, final Displayable active) {
    try {
        // dimensions
        int w = 0;
        int h = 0;
        Rectangle srcRect = (null == srcRect_) ? null : (Rectangle) srcRect_.clone();
        if (null != srcRect) {
            w = srcRect.width;
            h = srcRect.height;
        } else {
            w = (int) Math.ceil(layer.getLayerWidth());
            h = (int) Math.ceil(layer.getLayerHeight());
            srcRect = new Rectangle(0, 0, w, h);
        }
        Utils.log2("Loader.getFlatImage: using rectangle " + srcRect);
        /*
			 * output size including excess space for not entirely covered
			 * pixels
			 */
        final int ww = (int) Math.ceil(w * scale);
        final int hh = (int) Math.ceil(h * scale);
        /* The size of the buffered image to be generated */
        final int biw, bih;
        final double scaleP, scalePX, scalePY;
        // on scaling down to output resolution.
        if (quality) {
            if (ww * hh >= Math.pow(2, 30)) {
                // 1 GB
                // While perhaps scale could be increased to an image size of up to 2 GB, it is not advisable
                scaleP = scalePX = scalePY = scale;
                quality = false;
                biw = ww;
                bih = hh;
                Utils.log("Can't use 'quality' flag for getFlatAWTImage: would be too large");
            // If the image is larger than 2 GB, it will thrown a NegativeArraySizeException below and stop.
            } else {
                // Max area: the smallest of the srcRect at 100x magnification and 1 GB
                final double max_area = Math.min(srcRect.width * srcRect.height, Math.pow(2, 30));
                final double ratio = ww / (double) hh;
                // area = w * h
                // ratio = w / h
                // w = ratio * h
                // area = ratio * h * h
                // h = sqrt(area / ratio)
                // scaleP is then the ratio between the real-world height and the target height
                // (And clamp to a maximum of 1.0: above makes no sense)
                scaleP = Math.min(1.0, srcRect.height / Math.sqrt(max_area / ratio));
                biw = (int) Math.ceil(ww / scale);
                bih = (int) Math.ceil(hh / scale);
                /* compensate for excess space due to ceiling */
                scalePX = (double) biw / (double) ww * scale;
                scalePY = (double) bih / (double) hh * scale;
                Utils.log("getFlatAWTImage -- scale: " + scale + "; quality scale: " + scaleP);
            }
        } else {
            scaleP = scalePX = scalePY = scale;
            biw = ww;
            bih = hh;
        }
        // estimate image size
        final long n_bytes = (long) ((biw * bih * (ImagePlus.GRAY8 == type ? 1.0 : /*byte*/
        4.0)));
        Utils.log2("Flat image estimated size in bytes: " + Long.toString(n_bytes) + "  w,h : " + (int) Math.ceil(biw) + "," + (int) Math.ceil(bih) + (quality ? " (using 'quality' flag: scaling to " + scale + " is done later with area averaging)" : ""));
        releaseToFit(n_bytes);
        // go
        BufferedImage bi = null;
        switch(type) {
            case ImagePlus.GRAY8:
                bi = new BufferedImage(biw, bih, BufferedImage.TYPE_BYTE_INDEXED, GRAY_LUT);
                break;
            case ImagePlus.COLOR_RGB:
                bi = new BufferedImage(biw, bih, BufferedImage.TYPE_INT_ARGB);
                break;
            default:
                Utils.log2("Left bi,icm as null");
                break;
        }
        final Graphics2D g2d = bi.createGraphics();
        g2d.setColor(background);
        g2d.fillRect(0, 0, bi.getWidth(), bi.getHeight());
        g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        // TODO Stephan, test if that introduces offset vs nearest neighbor
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        // to smooth edges of the images
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        ArrayList<ZDisplayable> al_zdispl = null;
        if (null == al_displ) {
            al_displ = new ArrayList<Displayable>(layer.find(clazz, srcRect, true, true));
            al_zdispl = new ArrayList<ZDisplayable>((Collection) layer.getParent().findZDisplayables(clazz, layer, srcRect, true, true));
        } else {
            // separate ZDisplayables into their own array
            al_displ = new ArrayList<Displayable>(al_displ);
            final HashSet<ZDisplayable> az = new HashSet<ZDisplayable>();
            for (final Iterator<?> it = al_displ.iterator(); it.hasNext(); ) {
                final Object ob = it.next();
                if (ob instanceof ZDisplayable) {
                    it.remove();
                    az.add((ZDisplayable) ob);
                }
            }
            // order ZDisplayables by their stack order
            final ArrayList<ZDisplayable> al_zdispl2 = layer.getParent().getZDisplayables();
            for (final Iterator<ZDisplayable> it = al_zdispl2.iterator(); it.hasNext(); ) {
                if (!az.contains(it.next()))
                    it.remove();
            }
            al_zdispl = al_zdispl2;
        }
        // prepare the canvas for the srcRect and magnification
        final AffineTransform at_original = g2d.getTransform();
        final AffineTransform atc = new AffineTransform();
        atc.scale(scalePX, scalePY);
        atc.translate(-srcRect.x, -srcRect.y);
        at_original.preConcatenate(atc);
        g2d.setTransform(at_original);
        // Utils.log2("will paint: " + al_displ.size() + " displ and " + al_zdispl.size() + " zdispl");
        // int total = al_displ.size() + al_zdispl.size();
        int count = 0;
        boolean zd_done = false;
        final List<Layer> layers = layer.getParent().getColorCueLayerRange(layer);
        for (final Displayable d : al_displ) {
            // paint the ZDisplayables before the first label, if any
            if (!zd_done && d instanceof DLabel) {
                zd_done = true;
                for (final ZDisplayable zd : al_zdispl) {
                    if (!zd.isOutOfRepaintingClip(scaleP, srcRect, null)) {
                        zd.paint(g2d, srcRect, scaleP, active == zd, c_alphas, layer, layers);
                    }
                    count++;
                // Utils.log2("Painted " + count + " of " + total);
                }
            }
            if (!d.isOutOfRepaintingClip(scaleP, srcRect, null)) {
                d.paintOffscreen(g2d, srcRect, scaleP, active == d, c_alphas, layer, layers);
            // Utils.log("painted: " + d + "\n with: " + scaleP + ", " + c_alphas + ", " + layer);
            } else {
            // Utils.log2("out: " + d);
            }
            count++;
        // Utils.log2("Painted " + count + " of " + total);
        }
        if (!zd_done) {
            zd_done = true;
            for (final ZDisplayable zd : al_zdispl) {
                if (!zd.isOutOfRepaintingClip(scaleP, srcRect, null)) {
                    zd.paint(g2d, srcRect, scaleP, active == zd, c_alphas, layer, layers);
                }
                count++;
            // Utils.log2("Painted " + count + " of " + total);
            }
        }
        // ensure enough memory is available for the processor and a new awt from it
        // locks on its own
        releaseToFit((long) (n_bytes * 2.3));
        try {
            if (quality) {
                // need to scale back down
                Image scaled = null;
                if (!isMipMapsRegenerationEnabled() || scale >= 0.499) {
                    // there are no proper mipmaps above 50%, so there's need for SCALE_AREA_AVERAGING.
                    // very slow, but best by far
                    scaled = bi.getScaledInstance(ww, hh, Image.SCALE_AREA_AVERAGING);
                    if (ImagePlus.GRAY8 == type) {
                        // getScaledInstance generates RGB images for some reason.
                        final BufferedImage bi8 = new BufferedImage(ww, hh, BufferedImage.TYPE_BYTE_GRAY);
                        bi8.createGraphics().drawImage(scaled, 0, 0, null);
                        scaled.flush();
                        scaled = bi8;
                    }
                } else {
                    // faster, but requires gaussian blurred images (such as the mipmaps)
                    if (bi.getType() == BufferedImage.TYPE_BYTE_INDEXED) {
                        scaled = new BufferedImage(ww, hh, bi.getType(), GRAY_LUT);
                    } else {
                        scaled = new BufferedImage(ww, hh, bi.getType());
                    }
                    final Graphics2D gs = (Graphics2D) scaled.getGraphics();
                    // gs.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
                    gs.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                    gs.drawImage(bi, 0, 0, ww, hh, null);
                }
                bi.flush();
                return scaled;
            } else {
                // else the image was made scaled down already, and of the proper type
                return bi;
            }
        } catch (final OutOfMemoryError oome) {
            Utils.log("Not enough memory to create the ImagePlus. Try scaling it down or not using the 'quality' flag.");
        }
    } catch (final Exception e) {
        IJError.print(e);
    }
    return null;
}
Also used : ZDisplayable(ini.trakem2.display.ZDisplayable) Displayable(ini.trakem2.display.Displayable) Rectangle(java.awt.Rectangle) Image(java.awt.Image) BufferedImage(java.awt.image.BufferedImage) MipMapImage(ini.trakem2.display.MipMapImage) Layer(ini.trakem2.display.Layer) BufferedImage(java.awt.image.BufferedImage) IOException(java.io.IOException) FormatException(loci.formats.FormatException) Graphics2D(java.awt.Graphics2D) ZDisplayable(ini.trakem2.display.ZDisplayable) DLabel(ini.trakem2.display.DLabel) Collection(java.util.Collection) AffineTransform(java.awt.geom.AffineTransform) HashSet(java.util.HashSet)

Example 79 with Layer

use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.

the class ProjectTiler method createRetiledSibling.

/**
 * Take a {@link Project}, a size for the image tiles, and a target directory,
 * and create a new copy of the current project in that folder but with the underlying
 * images converted to tiles with a translation-only transform (saved as zipped TIFFs,
 * with extension ".tif.zip").
 * The new, returned {@link Project} represents the given project but with much
 * simpler transformations (just translation) for the images and a defined size for
 * the latter, which helps a lot regarding storage space of the XML (and parsing and
 * saving time) and performance when browsing layers (keep in mind that, for a 32k x 32k image,
 * at 100% zoom one would have to load a 32k x 32k image and render just a tiny bit
 * of it). The copied Project preserves the ID of the {@link Layer}s of the original
 * {@link Project}, as well as the dimensions; this means the copy is a sibling of
 * the original, and it is possible to send segmentations from one to the other "as is"
 * (directly, without having to transform along with the images which would not be possible).
 *
 * Image files are stored as
 *
 * The non-image objects of the given project are copied into the new project as well.
 *
 * @param srcProject The project to create a sibling of.
 * @param targetDirectory The directory in which to create all the necessary data and mipmap folders for the new Project.
 * @param tileWidth The width of the tiles to create for the data of the new project.
 * @param tileHeight The height of the tiles.
 * @param exportImageType Any of {@link ImagePlus#GRAY8}, {@link ImagePlus#GRAY16} or {@link ImagePlus#COLOR_RGB}, otherwise an {@link IllegalArgumentException} is thrown.
 * @param onlyVisibleImages Whether to consider visible images only.
 * @param nExportThreads Number of layers to export in parallel. Use a small number when original images are huge (such as larger than 4096 x 4096 pixels).
 * @param createMipMaps Whether to generate the mipmaps when done or not.
 *
 * @throws Exception IllegalArgumentException When {@code exportImageType} is not {@link ImagePlus#GRAY16} or {@link ImagePlus#COLOR_RGB}, or when the directory exists and cannot be written to.
 */
public static final Project createRetiledSibling(final Project srcProject, final String targetDirectory, final int tileWidth, final int tileHeight, final int exportImageType, final boolean onlyVisibleImages, final int nExportThreads, final boolean createMipMaps) throws Exception {
    // Validate exportImageType
    switch(exportImageType) {
        case ImagePlus.GRAY8:
        case ImagePlus.GRAY16:
        case ImagePlus.COLOR_RGB:
            break;
        default:
            throw new IllegalArgumentException("Can only accept GRAY8, GRAY16 or COLOR_RGB as values for 'exportImageType'!");
    }
    // Validate targetDirectory
    final File fdir = new File(targetDirectory);
    if (fdir.exists()) {
        if (!fdir.isDirectory() || !fdir.canWrite())
            throw new IllegalArgumentException("Invalid directory: not a directory or cannot write to: " + targetDirectory);
    } else {
        if (!fdir.mkdirs()) {
            throw new IllegalArgumentException("Cannot create directory at: " + targetDirectory);
        }
    }
    final String targetDir = Utils.fixDir(targetDirectory);
    // Create "data" directory
    final String dataDir = new StringBuilder(targetDir).append("data/").toString();
    final File fDataDir = new File(dataDir);
    if (fDataDir.exists() && (!fDataDir.isDirectory() || !fDataDir.canWrite())) {
        throw new IllegalArgumentException("Cannot create or write to 'data' directory in the targetDirectory at: " + targetDir);
    } else {
        fDataDir.mkdir();
    }
    // Create new Project, plain, without any automatic creation of a Layer or a Display
    final Project newProject = Project.newFSProject("blank", null, targetDir, false);
    final LayerSet newLayerSet = newProject.getRootLayerSet();
    newLayerSet.setCalibration(srcProject.getRootLayerSet().getCalibrationCopy());
    if (!createMipMaps) {
        Utils.log("MipMaps are DISABLED:\n --> When done, right-click and choose 'Display - Properties...' and enable mipmaps,\n     and then run 'Project - Regenerate all mipmaps'\n");
        newProject.getLoader().setMipMapsRegeneration(false);
        Utils.log("mipmaps enabled? " + newProject.getLoader().isMipMapsRegenerationEnabled());
    }
    // Copy the Template Tree of types
    newProject.resetRootTemplateThing(srcProject.getRootTemplateThing().clone(newProject, true), null);
    for (final TemplateThing tt : newProject.getRootTemplateThing().getUniqueTypes(new HashMap<String, TemplateThing>()).values()) {
        newProject.addUniqueType(tt);
    }
    // Clone layers with the exact same IDs, so that the two projects are siblings at the layer-level:
    // (Being siblings allows for treelines, arealists, etc. to be transferred from one to another "as is").
    final List<Layer> srcLayers = srcProject.getRootLayerSet().getLayers();
    final List<Layer> newLayers = new ArrayList<Layer>();
    for (final Layer srcLayer : srcLayers) {
        final Layer newLayer = new Layer(newProject, srcLayer.getId(), srcLayer.getZ(), srcLayer.getThickness());
        // to update the ID generator in FSLoader
        newLayer.addToDatabase();
        newLayerSet.add(newLayer);
        newLayers.add(newLayer);
        newProject.getRootLayerThing().addChild(new LayerThing(newProject.getRootLayerThing().getChildTemplate("layer"), newProject, newLayer));
    }
    newProject.getLayerTree().rebuild();
    // Update the LayerSet
    newLayerSet.setDimensions(srcProject.getRootLayerSet().getLayerWidth(), srcProject.getRootLayerSet().getLayerHeight(), LayerSet.NORTHWEST);
    Display.updateLayerScroller(newLayerSet);
    Display.update(newLayerSet);
    // Copy template from the src Project
    // (It's done after creating layers so the IDs will not collide with those of the Layers)
    newProject.resetRootTemplateThing(srcProject.getRootTemplateThing().clone(newProject, false), null);
    // Export tiles as new Patch instances, creating new image files in disk
    final int numThreads = Math.max(1, Math.min(nExportThreads, Runtime.getRuntime().availableProcessors()));
    int i = 0;
    for (final Layer srcLayer : srcLayers) {
        Utils.log("Processing layer " + (i + 1) + "/" + srcLayers.size() + " -- " + new Date());
        final int layerIndex = i++;
        // Create subDirectory
        final String dir = dataDir + "/" + layerIndex + "/";
        new File(dir).mkdir();
        // Create a new Layer with the same Z and thickness
        final Layer newLayer = newLayers.get(layerIndex);
        // Export layer tiles
        final ArrayList<Patch> patches = new ArrayList<Patch>();
        if (ImagePlus.GRAY16 == exportImageType) {
            Process.progressive(ExportUnsignedShort.exportTiles(srcLayer, tileWidth, tileHeight, onlyVisibleImages), new CountingTaskFactory<Callable<ExportedTile>, Patch>() {

                public Patch process(final Callable<ExportedTile> c, final int index) {
                    try {
                        // Create the tile
                        final ExportedTile t = c.call();
                        // Store the file
                        final String title = layerIndex + "-" + index;
                        final String path = dir + title + ".tif.zip";
                        final ImagePlus imp = new ImagePlus(title, t.sp);
                        if (!new FileSaver(imp).saveAsZip(path)) {
                            throw new Exception("Could not save tile: " + path);
                        }
                        // Create a Patch
                        final Patch patch = new Patch(newProject, title, t.x, t.y, imp);
                        patch.setLocked(true);
                        newProject.getLoader().addedPatchFrom(path, patch);
                        return patch;
                    } catch (Exception e) {
                        IJError.print(e);
                        return null;
                    }
                }
            }, patches, numThreads);
        } else {
            // GRAY8 or COLOR_RGB: created from mipmaps
            Process.progressive(tileSequence(srcLayer, tileWidth, tileHeight, onlyVisibleImages), new CountingTaskFactory<Rectangle, Patch>() {

                @Override
                public Patch process(final Rectangle bounds, final int index) {
                    try {
                        // Create the tile
                        final ImagePlus imp = srcLayer.getProject().getLoader().getFlatImage(srcLayer, bounds, 1.0, -1, exportImageType, Patch.class, null, false, Color.black);
                        final String title = layerIndex + "-" + index;
                        imp.setTitle(title);
                        final String path = dir + title + ".tif.zip";
                        if (!new FileSaver(imp).saveAsZip(path)) {
                            throw new Exception("Could not save tile: " + path);
                        }
                        // Create a Patch
                        final Patch patch = new Patch(newProject, title, bounds.x, bounds.y, imp);
                        patch.setLocked(true);
                        newProject.getLoader().addedPatchFrom(path, patch);
                        return patch;
                    } catch (Exception e) {
                        IJError.print(e);
                        return null;
                    }
                }
            }, patches, numThreads);
        }
        // Add all Patches to the new Layer
        for (final Patch p : patches) {
            newLayer.add(p);
        }
    }
    // Copy all segmentations "As is"
    final ProjectThing root = srcProject.getRootProjectThing();
    if (null != root.getChildren() && !root.getChildren().isEmpty()) {
        final ProjectThing source_pt = srcProject.getRootProjectThing().getChildren().get(0);
        // "As is"
        final int transfer_mode = 0;
        final ProjectThing landing_parent = newProject.getRootProjectThing();
        srcProject.getProjectTree().rawSendToSiblingProject(source_pt, transfer_mode, newProject, landing_parent);
    }
    // Copy all floating text labels
    i = 0;
    for (final Layer srcLayer : srcLayers) {
        for (final DLabel srcLabel : srcLayer.getAll(DLabel.class)) {
            newLayers.get(i++).add(srcLabel.clone(newProject, false));
        }
    }
    if (createMipMaps) {
        final LinkedList<Future<?>> fus = new LinkedList<Future<?>>();
        final int batch = Runtime.getRuntime().availableProcessors();
        for (final Layer newLayer : newLayers) {
            for (final Patch p : newLayer.getAll(Patch.class)) {
                fus.add(p.updateMipMaps());
                // Don't build-up too much
                if (fus.size() > batch * 3) {
                    while (fus.size() > batch) {
                        try {
                            fus.removeFirst().get();
                        } catch (Exception e) {
                            IJError.print(e);
                        }
                    }
                }
            }
        }
        Utils.wait(fus);
    }
    // Save:
    newProject.saveAs(targetDir + "exported.xml", false);
    return newProject;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) Callable(java.util.concurrent.Callable) FileSaver(ij.io.FileSaver) ProjectThing(ini.trakem2.tree.ProjectThing) LayerSet(ini.trakem2.display.LayerSet) LayerThing(ini.trakem2.tree.LayerThing) Layer(ini.trakem2.display.Layer) ImagePlus(ij.ImagePlus) Date(java.util.Date) LinkedList(java.util.LinkedList) Project(ini.trakem2.Project) DLabel(ini.trakem2.display.DLabel) TemplateThing(ini.trakem2.tree.TemplateThing) Future(java.util.concurrent.Future) File(java.io.File) Patch(ini.trakem2.display.Patch) ExportedTile(mpicbg.trakem2.transform.ExportedTile)

Example 80 with Layer

use of ini.trakem2.display.Layer in project TrakEM2 by trakem2.

the class StaleFiles method delete.

/**
 * Generic method called by other methods of this class.
 */
public static final boolean delete(final Project project, final String topDir, final Path g) {
    if (null == topDir)
        return true;
    // Collect the set of files to keep
    final HashSet<String> keepers = new HashSet<String>();
    for (final Layer l : project.getRootLayerSet().getLayers()) {
        for (final Patch p : l.getAll(Patch.class)) {
            String path = g.get(p);
            if (null != path)
                keepers.add(path);
        }
    }
    // Iterate all directories, recursively
    final String extension = g.extension();
    final LinkedList<File> subdirs = new LinkedList<File>();
    subdirs.add(new File(topDir));
    final AtomicInteger counter = new AtomicInteger(0);
    final ExecutorService exec = Utils.newFixedThreadPool(Math.max(2, Runtime.getRuntime().availableProcessors()), "Stale-file-remover");
    while (!subdirs.isEmpty()) {
        final File fdir = subdirs.removeFirst();
        final String absPath = fdir.getAbsolutePath();
        for (final String s : fdir.list()) {
            final String path = absPath + "/" + s;
            if (s.endsWith(extension)) {
                if (keepers.contains(path))
                    continue;
                // Else, delete the file, which is by definition stale
                exec.submit(new Runnable() {

                    public void run() {
                        if (!new File(path).delete()) {
                            Utils.log2("Failed to delete: " + path);
                            counter.incrementAndGet();
                        }
                    }
                });
            } else {
                final File f = new File(path);
                if (f.isDirectory()) {
                    subdirs.add(f);
                }
            }
        }
    }
    // Do not accept more tasks, but execute all submitted tasks
    exec.shutdown();
    // Wait maximum for an unreasonable amount of time
    try {
        exec.awaitTermination(1, TimeUnit.DAYS);
    } catch (InterruptedException e) {
        IJError.print(e);
    }
    if (counter.get() > 0) {
        Utils.log("ERROR: failed to delete " + counter.get() + " files.\n        See the stdout log for details.");
    }
    return 0 == counter.get();
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ExecutorService(java.util.concurrent.ExecutorService) Layer(ini.trakem2.display.Layer) Patch(ini.trakem2.display.Patch) File(java.io.File) LinkedList(java.util.LinkedList) HashSet(java.util.HashSet)

Aggregations

Layer (ini.trakem2.display.Layer)61 ArrayList (java.util.ArrayList)52 Patch (ini.trakem2.display.Patch)43 Rectangle (java.awt.Rectangle)34 HashSet (java.util.HashSet)27 ImagePlus (ij.ImagePlus)26 Displayable (ini.trakem2.display.Displayable)25 AffineTransform (java.awt.geom.AffineTransform)23 GenericDialog (ij.gui.GenericDialog)22 Worker (ini.trakem2.utils.Worker)22 Point (mpicbg.models.Point)22 HashMap (java.util.HashMap)21 Point (java.awt.Point)19 Area (java.awt.geom.Area)19 NoninvertibleTransformException (java.awt.geom.NoninvertibleTransformException)18 File (java.io.File)16 Future (java.util.concurrent.Future)16 LayerSet (ini.trakem2.display.LayerSet)15 ExecutorService (java.util.concurrent.ExecutorService)14 Collection (java.util.Collection)13