Search in sources :

Example 51 with Layer

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

the class TMLHandler method getProjectData.

/**
 * returns 4 objects packed in an array:
 *	 <pre>
 *	 [0] = root TemplateThing
 *	 [1] = root ProjectThing (contains Project instance)
 *	 [2] = root LayerThing (contains the top-level LayerSet)
 *	 [3] = expanded states of all ProjectThing objects
 *	 </pre>
 * <p>
 * Also, triggers the reconstruction of links and assignment of Displayable objects to their layer.
 * </p>
 */
public Object[] getProjectData(final boolean open_displays) {
    if (null == project)
        return null;
    this.open_displays = open_displays;
    // Links exist between Displayable objects.
    for (final Displayable d : ht_displayables.values()) {
        String olinks = ht_links.get(d);
        // not linked
        if (null == olinks)
            continue;
        String[] links = olinks.split(",");
        Long lid = null;
        for (int i = 0; i < links.length; i++) {
            try {
                lid = new Long(links[i]);
            } catch (NumberFormatException nfe) {
                Utils.log2("Ignoring incorrectly formated link '" + links[i] + "' for ob " + d);
                continue;
            }
            Displayable partner = ht_displayables.get(lid);
            if (null != partner)
                d.link(partner, false);
            else
                Utils.log("TMLHandler: can't find partner with id=" + links[i] + " for Displayable with id=" + d.getId());
        }
    }
    // 1.2 - Reconstruct linked properties
    for (final Map.Entry<Displayable, Map<Long, Map<String, String>>> lpe : all_linked_props.entrySet()) {
        final Displayable origin = lpe.getKey();
        for (final Map.Entry<Long, Map<String, String>> e : lpe.getValue().entrySet()) {
            final Displayable target = ht_displayables.get(e.getKey());
            if (null == target) {
                Utils.log("Setting linked properties for origin " + origin.getId() + ":\n\t* Could not find target displayable #" + e.getKey());
                continue;
            }
            origin.setLinkedProperties(target, e.getValue());
        }
    }
    // 2 - Add Displayable objects to ProjectThing that can contain them
    for (final Map.Entry<Long, ProjectThing> entry : ht_oid_pt.entrySet()) {
        ProjectThing pt = entry.getValue();
        Object od = ht_displayables.remove(entry.getKey());
        // Utils.log("==== processing: Displayable [" + od + "]  vs. ProjectThing [" + pt + "]");
        if (null != od) {
            pt.setObject(od);
        } else {
            Utils.log("#### Failed to find a Displayable for ProjectThing " + pt + " #####");
        }
    }
    // 3 - Assign a layer pointer to ZDisplayable objects
    for (final ZDisplayable zd : ht_zdispl.values()) {
        // zd.setLayer((Layer)zd.getLayerSet().getLayers().get(0));
        zd.setLayer(zd.getLayerSet().getLayer(0));
    }
    // 4 - Assign layers to Treeline nodes
    for (final Layer la : al_layers) {
        final List<Node<?>> list = node_layer_table.remove(la.getId());
        if (null == list)
            continue;
        for (final Node<?> nd : list) nd.setLayer(la);
    }
    if (!node_layer_table.isEmpty()) {
        Utils.log("ERROR: node_layer_table is not empty!");
    }
    // 5 - Assign root nodes to Treelines, now that all nodes have a layer
    for (final Map.Entry<Tree<?>, Node<?>> e : tree_root_nodes.entrySet()) {
        if (null == e.getValue()) {
            // Utils.log2("Ignoring, applies to new Treeline format only.");
            continue;
        }
        // Can't compile with <?>
        // will generate node caches of each Treeline
        e.getKey().setRoot((Node) e.getValue());
    }
    tree_root_nodes.clear();
    // Assign colors to nodes
    for (final Map.Entry<Color, Collection<Node<?>>> e : node_colors.entrySet()) {
        for (final Node<?> nd : e.getValue()) {
            nd.setColor(e.getKey());
        }
    }
    node_colors.clear();
    // 6 - Run legacy operations
    for (final Runnable r : legacy) {
        r.run();
    }
    try {
        // Create a table with all layer ids vs layer instances:
        final HashMap<Long, Layer> ht_lids = new HashMap<Long, Layer>();
        for (final Layer layer : al_layers) {
            ht_lids.put(new Long(layer.getId()), layer);
        }
        // Spawn threads to recreate buckets, starting from the subset of displays to open
        int n = Runtime.getRuntime().availableProcessors();
        switch(n) {
            case 1:
                break;
            case 2:
            case 3:
            case 4:
                n--;
                break;
            default:
                n -= 2;
                break;
        }
        final ExecutorService exec = Utils.newFixedThreadPool(n, "TMLHandler-recreateBuckets");
        final Set<Long> dlids = new HashSet<Long>();
        final LayerSet layer_set = (LayerSet) root_lt.getObject();
        final List<Future<?>> fus = new ArrayList<Future<?>>();
        final List<Future<?>> fus2 = new ArrayList<Future<?>>();
        for (final HashMap<String, String> ht_attributes : al_displays) {
            String ob = ht_attributes.get("layer_id");
            if (null == ob)
                continue;
            final Long lid = new Long(ob);
            dlids.add(lid);
            final Layer la = ht_lids.get(lid);
            if (null == la) {
                ht_lids.remove(lid);
                continue;
            }
            // to open later:
            new Display(project, Long.parseLong(ht_attributes.get("id")), la, ht_attributes);
            fus.add(exec.submit(new Runnable() {

                public void run() {
                    la.recreateBuckets();
                }
            }));
        }
        fus.add(exec.submit(new Runnable() {

            public void run() {
                // only for ZDisplayable
                layer_set.recreateBuckets(false);
            }
        }));
        // Ensure launching:
        if (dlids.isEmpty() && layer_set.size() > 0) {
            dlids.add(layer_set.getLayer(0).getId());
        }
        final List<Layer> layers = layer_set.getLayers();
        for (final Long lid : new HashSet<Long>(dlids)) {
            fus.add(exec.submit(new Runnable() {

                public void run() {
                    int start = layer_set.indexOf(layer_set.getLayer(lid.longValue()));
                    int next = start + 1;
                    int prev = start - 1;
                    while (next < layer_set.size() || prev > -1) {
                        if (prev > -1) {
                            final Layer lprev = layers.get(prev);
                            synchronized (dlids) {
                                if (dlids.add(lprev.getId())) {
                                    // returns true if not there already
                                    fus2.add(exec.submit(new Runnable() {

                                        public void run() {
                                            lprev.recreateBuckets();
                                        }
                                    }));
                                }
                            }
                            prev--;
                        }
                        if (next < layers.size()) {
                            final Layer lnext = layers.get(next);
                            synchronized (dlids) {
                                if (dlids.add(lnext.getId())) {
                                    // returns true if not there already
                                    fus2.add(exec.submit(new Runnable() {

                                        public void run() {
                                            lnext.recreateBuckets();
                                        }
                                    }));
                                }
                            }
                            next++;
                        }
                    }
                    Utils.log2("done recreateBuckets chunk");
                }
            }));
        }
        Utils.wait(fus);
        exec.submit(new Runnable() {

            public void run() {
                Utils.log2("waiting for TMLHandler fus...");
                Utils.wait(fus2);
                Utils.log2("done waiting TMLHandler fus.");
                exec.shutdown();
            }
        });
    } catch (Throwable t) {
        IJError.print(t);
    }
    return new Object[] { root_tt, root_pt, root_lt, ht_pt_expanded };
}
Also used : HashMap(java.util.HashMap) Node(ini.trakem2.display.Node) ArrayList(java.util.ArrayList) AreaTree(ini.trakem2.display.AreaTree) Tree(ini.trakem2.display.Tree) ProjectThing(ini.trakem2.tree.ProjectThing) HashSet(java.util.HashSet) Displayable(ini.trakem2.display.Displayable) ZDisplayable(ini.trakem2.display.ZDisplayable) LayerSet(ini.trakem2.display.LayerSet) Color(java.awt.Color) Layer(ini.trakem2.display.Layer) ZDisplayable(ini.trakem2.display.ZDisplayable) ExecutorService(java.util.concurrent.ExecutorService) Collection(java.util.Collection) Future(java.util.concurrent.Future) Map(java.util.Map) HashMap(java.util.HashMap) Display(ini.trakem2.display.Display)

Example 52 with Layer

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

the class ProjectThing method createChild.

public ProjectThing createChild(String type) {
    // create the Displayable
    TemplateThing tt = template.getChildTemplate(type);
    if (null == tt) {
        Utils.log2("Can't create a child of type " + type);
        return null;
    }
    Object ob = project.makeObject(tt);
    Layer layer = null;
    if (ob instanceof Displayable) {
        // which layer to add it to? Get it from the front Display
        layer = Display.getFrontLayer(this.project);
        if (null == layer) {
            Utils.showMessage("Open a display first!");
            ((DBObject) ob).removeFromDatabase();
            return null;
        }
    }
    // wrap it in a new ProjectThing
    ProjectThing pt = null;
    try {
        pt = new ProjectThing(tt, project, ob);
    } catch (Exception e) {
        IJError.print(e);
        return null;
    }
    // add it here as child
    addChild(pt);
    // finally, add it to the layer if appropriate
    if (null != layer) {
        if (ob instanceof ZDisplayable) {
            layer.getParent().add((ZDisplayable) ob);
        } else {
            layer.add((Displayable) ob);
        }
    }
    // finally, return it to be added to the ProjectTree as a new node
    return pt;
}
Also used : ZDisplayable(ini.trakem2.display.ZDisplayable) ZDisplayable(ini.trakem2.display.ZDisplayable) Displayable(ini.trakem2.display.Displayable) DBObject(ini.trakem2.persistence.DBObject) Layer(ini.trakem2.display.Layer) DBObject(ini.trakem2.persistence.DBObject)

Example 53 with Layer

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

the class ProjectTree method mousePressed.

public void mousePressed(final MouseEvent me) {
    super.dispatcher.execSwing(new Runnable() {

        public void run() {
            if (!me.getSource().equals(ProjectTree.this) || !project.isInputEnabled()) {
                return;
            }
            final int x = me.getX();
            final int y = me.getY();
            // find the node and set it selected
            final TreePath path = getPathForLocation(x, y);
            if (null == path) {
                return;
            }
            ProjectTree.this.setSelectionPath(path);
            selected_node = (DefaultMutableTreeNode) path.getLastPathComponent();
            if (2 == me.getClickCount() && !me.isPopupTrigger() && MouseEvent.BUTTON1 == me.getButton()) {
                // show in the front Display
                if (null == selected_node)
                    return;
                Object obt = selected_node.getUserObject();
                if (!(obt instanceof ProjectThing))
                    return;
                ProjectThing thing = (ProjectThing) obt;
                thing.setVisible(true);
                Object obd = thing.getObject();
                if (obd instanceof Displayable) {
                    // additionaly, get the front Display (or make a new one if none) and show in it the layer in which the Displayable object is contained.
                    Displayable displ = (Displayable) obd;
                    Display.showCentered(displ.getLayer(), displ, true, me.isShiftDown());
                }
                return;
            } else if (me.isPopupTrigger() || (ij.IJ.isMacOSX() && me.isControlDown()) || MouseEvent.BUTTON2 == me.getButton() || 0 != (me.getModifiers() & Event.META_MASK)) {
                // the last block is from ij.gui.ImageCanvas, aparently to make the right-click work on windows?
                JPopupMenu popup = getPopupMenu(selected_node);
                if (null == popup)
                    return;
                popup.show(ProjectTree.this, x, y);
                return;
            }
        }
    });
}
Also used : Displayable(ini.trakem2.display.Displayable) ZDisplayable(ini.trakem2.display.ZDisplayable) TreePath(javax.swing.tree.TreePath) DefaultMutableTreeNode(javax.swing.tree.DefaultMutableTreeNode) DBObject(ini.trakem2.persistence.DBObject) JPopupMenu(javax.swing.JPopupMenu)

Example 54 with Layer

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

the class FSLoader method importStackAsPatches.

/**
 * Returns the last Patch.
 */
protected Patch importStackAsPatches(final Project project, final Layer first_layer, final double x, final double y, final ImagePlus imp_stack, final boolean as_copy, final String filepath) {
    Utils.log2("FSLoader.importStackAsPatches filepath=" + filepath);
    String target_dir = null;
    if (as_copy) {
        DirectoryChooser dc = new DirectoryChooser("Folder to save images");
        target_dir = dc.getDirectory();
        // user canceled dialog
        if (null == target_dir)
            return null;
        if (IJ.isWindows())
            target_dir = target_dir.replace('\\', '/');
        if (target_dir.length() - 1 != target_dir.lastIndexOf('/')) {
            target_dir += "/";
        }
    }
    // Double.MAX_VALUE is a flag to indicate "add centered"
    double pos_x = Double.MAX_VALUE != x ? x : first_layer.getLayerWidth() / 2 - imp_stack.getWidth() / 2;
    double pos_y = Double.MAX_VALUE != y ? y : first_layer.getLayerHeight() / 2 - imp_stack.getHeight() / 2;
    final double thickness = first_layer.getThickness();
    final String title = Utils.removeExtension(imp_stack.getTitle()).replace(' ', '_');
    Utils.showProgress(0);
    Patch previous_patch = null;
    final int n = imp_stack.getStackSize();
    final ImageStack stack = imp_stack.getStack();
    final boolean virtual = stack.isVirtual();
    final VirtualStack vs = virtual ? (VirtualStack) stack : null;
    for (int i = 1; i <= n; i++) {
        Layer layer = first_layer;
        double z = first_layer.getZ() + (i - 1) * thickness;
        // will create new layer if not found
        if (i > 1)
            layer = first_layer.getParent().getLayer(z, thickness, true);
        if (null == layer) {
            Utils.log("Display.importStack: could not create new layers.");
            return null;
        }
        String patch_path = null;
        ImagePlus imp_patch_i = null;
        if (virtual) {
            // because we love inefficiency, every time all this is done again
            // VirtualStack vs = (VirtualStack)imp_stack.getStack();
            String vs_dir = vs.getDirectory().replace('\\', '/');
            if (!vs_dir.endsWith("/"))
                vs_dir += "/";
            String iname = vs.getFileName(i);
            patch_path = vs_dir + iname;
            Utils.log2("virtual stack: patch path is " + patch_path);
            releaseToFit(new File(patch_path).length() * 3);
            Utils.log2(i + " : " + patch_path);
            imp_patch_i = openImage(patch_path);
        } else {
            ImageProcessor ip = stack.getProcessor(i);
            if (as_copy)
                ip = ip.duplicate();
            imp_patch_i = new ImagePlus(title + "__slice=" + i, ip);
        }
        String label = stack.getSliceLabel(i);
        if (null == label)
            label = "";
        Patch patch = null;
        if (as_copy) {
            patch_path = target_dir + cleanSlashes(imp_patch_i.getTitle()) + ".zip";
            ini.trakem2.io.ImageSaver.saveAsZip(imp_patch_i, patch_path);
            patch = new Patch(project, label + " " + title + " " + i, pos_x, pos_y, imp_patch_i);
        } else if (virtual) {
            patch = new Patch(project, label, pos_x, pos_y, imp_patch_i);
        } else {
            patch_path = filepath + "-----#slice=" + i;
            // Utils.log2("path is "+ patch_path);
            final AffineTransform atp = new AffineTransform();
            atp.translate(pos_x, pos_y);
            patch = new Patch(project, getNextId(), label + " " + title + " " + i, imp_stack.getWidth(), imp_stack.getHeight(), imp_stack.getWidth(), imp_stack.getHeight(), imp_stack.getType(), false, imp_stack.getProcessor().getMin(), imp_stack.getProcessor().getMax(), atp);
            patch.addToDatabase();
        // Utils.log2("type is " + imp_stack.getType());
        }
        Utils.log2("B: " + i + " : " + patch_path);
        addedPatchFrom(patch_path, patch);
        if (!as_copy && !virtual) {
            if (// each slice separately
            virtual)
                // each slice separately
                cache(patch, imp_patch_i);
            else
                // uses the entire stack, shared among all Patch instances
                cache(patch, imp_stack);
        }
        // submit for regeneration
        if (isMipMapsRegenerationEnabled())
            regenerateMipMaps(patch);
        if (null != previous_patch)
            patch.link(previous_patch);
        layer.add(patch);
        previous_patch = patch;
        Utils.showProgress(i * (1.0 / n));
    }
    Utils.showProgress(1.0);
    // return the last patch
    return previous_patch;
}
Also used : ImageStack(ij.ImageStack) Layer(ini.trakem2.display.Layer) ImagePlus(ij.ImagePlus) FloatImagePlus(net.imglib2.img.imageplus.FloatImagePlus) ImageProcessor(ij.process.ImageProcessor) VirtualStack(ij.VirtualStack) AffineTransform(java.awt.geom.AffineTransform) Patch(ini.trakem2.display.Patch) File(java.io.File) DirectoryChooser(ij.io.DirectoryChooser)

Example 55 with Layer

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

the class FSLoader method generateMipMaps.

/**
 * Given an image and its source file name (without directory prepended), generate
 * a pyramid of images until reaching an image not smaller than 32x32 pixels.
 * <p>
 * Such images are stored as jpeg 85% quality in a folder named trakem2.mipmaps.
 * </p>
 * <p>
 * The Patch id and the right extension will be appended to the filename in all cases.
 * </p>
 * <p>
 * Any equally named files will be overwritten.
 * </p>
 */
protected boolean generateMipMaps(final Patch patch) {
    Utils.log2("mipmaps for " + patch);
    final String path = getAbsolutePath(patch);
    if (null == path) {
        Utils.log("generateMipMaps: null path for Patch " + patch);
        cannot_regenerate.add(patch);
        return false;
    }
    if (hs_unloadable.contains(patch)) {
        FilePathRepair.add(patch);
        return false;
    }
    synchronized (gm_lock) {
        try {
            if (null == dir_mipmaps)
                createMipMapsDir(null);
            if (null == dir_mipmaps || isURL(dir_mipmaps))
                return false;
        } catch (Exception e) {
            IJError.print(e);
        }
    }
    /**
     * Record Patch as modified
     */
    touched_mipmaps.add(patch);
    /**
     * Remove serialized features, if any
     */
    removeSerializedFeatures(patch);
    /**
     * Remove serialized pointmatches, if any
     */
    removeSerializedPointMatches(patch);
    /**
     * Alpha mask: setup to check if it was modified while regenerating.
     */
    final long alpha_mask_id = patch.getAlphaMaskId();
    final int resizing_mode = patch.getProject().getMipMapsMode();
    try {
        ImageProcessor ip;
        ByteProcessor alpha_mask = null;
        ByteProcessor outside_mask = null;
        int type = patch.getType();
        // Aggressive cache freeing
        releaseToFit(patch.getOWidth() * patch.getOHeight() * 4 + MIN_FREE_BYTES);
        // Obtain an image which may be coordinate-transformed, and an alpha mask.
        Patch.PatchImage pai = patch.createTransformedImage();
        if (null == pai || null == pai.target) {
            Utils.log("Can't regenerate mipmaps for patch " + patch);
            cannot_regenerate.add(patch);
            return false;
        }
        ip = pai.target;
        // can be null
        alpha_mask = pai.mask;
        // can be null
        outside_mask = pai.outside;
        pai = null;
        // Old style:
        // final String filename = new StringBuilder(new File(path).getName()).append('.').append(patch.getId()).append(mExt).toString();
        // New style:
        final String filename = createMipMapRelPath(patch, mExt);
        int w = ip.getWidth();
        int h = ip.getHeight();
        // sigma = sqrt(2^level - 0.5^2)
        // where 0.5 is the estimated sigma for a full-scale image
        // which means sigma = 0.75 for the full-scale image (has level 0)
        // prepare a 0.75 sigma image from the original
        double min = patch.getMin(), max = patch.getMax();
        // (The -1,-1 are flags really for "not set")
        if (-1 == min && -1 == max) {
            switch(type) {
                case ImagePlus.COLOR_RGB:
                case ImagePlus.COLOR_256:
                case ImagePlus.GRAY8:
                    patch.setMinAndMax(0, 255);
                    break;
                // Find and flow through to default:
                case ImagePlus.GRAY16:
                    ((ij.process.ShortProcessor) ip).findMinAndMax();
                    patch.setMinAndMax(ip.getMin(), ip.getMax());
                    break;
                case ImagePlus.GRAY32:
                    ((FloatProcessor) ip).findMinAndMax();
                    patch.setMinAndMax(ip.getMin(), ip.getMax());
                    break;
            }
            // may have changed
            min = patch.getMin();
            max = patch.getMax();
        }
        // Set for the level 0 image, which is a duplicate of the one in the cache in any case
        ip.setMinAndMax(min, max);
        // ImageJ no longer stretches the bytes for ByteProcessor with setMinAndmax
        if (ByteProcessor.class == ip.getClass()) {
            if (0 != min && 255 != max) {
                final byte[] b = (byte[]) ip.getPixels();
                final double scale = 255 / (max - min);
                for (int i = 0; i < b.length; ++i) {
                    final int val = b[i] & 0xff;
                    if (val < min)
                        b[i] = 0;
                    else
                        b[i] = (byte) Math.min(255, ((val - min) * scale));
                }
            }
        }
        // Proper support for LUT images: treat them as RGB
        if (ip.isColorLut() || type == ImagePlus.COLOR_256) {
            ip = ip.convertToRGB();
            type = ImagePlus.COLOR_RGB;
        }
        final int first_mipmap_level_saved = patch.getProject().getFirstMipMapLevelSaved();
        if (Loader.AREA_DOWNSAMPLING == resizing_mode) {
            long t0 = System.currentTimeMillis();
            final ImageBytes[] b = DownsamplerMipMaps.create(patch, type, ip, alpha_mask, outside_mask);
            long t1 = System.currentTimeMillis();
            for (int i = 0; i < b.length; ++i) {
                if (i < first_mipmap_level_saved) {
                    // Ignore level i
                    if (null != b[i])
                        CachingThread.storeForReuse(b[i].c);
                } else {
                    boolean written = mmio.save(getLevelDir(dir_mipmaps, i) + filename, b[i].c, b[i].width, b[i].height, 0.85f);
                    if (!written) {
                        Utils.log("Failed to save mipmap with area downsampling at level=" + i + " for patch " + patch);
                        cannot_regenerate.add(patch);
                        break;
                    }
                }
            }
            long t2 = System.currentTimeMillis();
            System.out.println("MipMaps with area downsampling: creation took " + (t1 - t0) + "ms, saving took " + (t2 - t1) + "ms, total: " + (t2 - t0) + "ms\n");
        } else if (Loader.GAUSSIAN == resizing_mode) {
            if (ImagePlus.COLOR_RGB == type) {
                // TODO releaseToFit proper
                releaseToFit(w * h * 4 * 10);
                final ColorProcessor cp = (ColorProcessor) ip;
                final FloatProcessorT2 red = new FloatProcessorT2(w, h, 0, 255);
                cp.toFloat(0, red);
                final FloatProcessorT2 green = new FloatProcessorT2(w, h, 0, 255);
                cp.toFloat(1, green);
                final FloatProcessorT2 blue = new FloatProcessorT2(w, h, 0, 255);
                cp.toFloat(2, blue);
                FloatProcessorT2 alpha;
                final FloatProcessorT2 outside;
                if (null != alpha_mask) {
                    alpha = new FloatProcessorT2(alpha_mask);
                } else {
                    alpha = null;
                }
                if (null != outside_mask) {
                    outside = new FloatProcessorT2(outside_mask);
                    if (null == alpha) {
                        alpha = outside;
                        alpha_mask = outside_mask;
                    }
                } else {
                    outside = null;
                }
                final String target_dir0 = getLevelDir(dir_mipmaps, 0);
                if (Thread.currentThread().isInterrupted())
                    return false;
                // Generate level 0 first:
                if (0 == first_mipmap_level_saved) {
                    boolean written;
                    if (null == alpha) {
                        written = mmio.save(cp, target_dir0 + filename, 0.85f, false);
                    } else {
                        written = mmio.save(target_dir0 + filename, P.asRGBABytes((int[]) cp.getPixels(), (byte[]) alpha_mask.getPixels(), null == outside ? null : (byte[]) outside_mask.getPixels()), w, h, 0.85f);
                    }
                    if (!written) {
                        Utils.log("Failed to save mipmap for COLOR_RGB, 'alpha = " + alpha + "', level = 0  for  patch " + patch);
                        cannot_regenerate.add(patch);
                    }
                }
                // Generate all other mipmap levels
                // TODO: for best performance, it should start from a direct Gaussian downscaling at the first level to write.
                // the scale level. Proper scale is: 1 / pow(2, k)
                int k = 0;
                do {
                    if (Thread.currentThread().isInterrupted())
                        return false;
                    // 1 - Prepare values for the next scaled image
                    k++;
                    // 2 - Check that the target folder for the desired scale exists
                    final String target_dir = getLevelDir(dir_mipmaps, k);
                    if (null == target_dir)
                        break;
                    // 3 - Blur the previous image to 0.75 sigma, and scale it
                    // will resize 'red' FloatProcessor in place.
                    final byte[] r = gaussianBlurResizeInHalf(red);
                    // idem
                    final byte[] g = gaussianBlurResizeInHalf(green);
                    // idem
                    final byte[] b = gaussianBlurResizeInHalf(blue);
                    // idem
                    final byte[] a = null == alpha ? null : gaussianBlurResizeInHalf(alpha);
                    if (null != outside) {
                        final byte[] o;
                        if (alpha != outside)
                            // idem
                            o = gaussianBlurResizeInHalf(outside);
                        else
                            o = a;
                        // If there was no alpha mask, alpha is the outside itself
                        for (int i = 0; i < o.length; i++) {
                            // TODO I am sure there is a bitwise operation to do this in one step. Some thing like: a[i] &= 127;
                            if ((o[i] & 0xff) != 255)
                                a[i] = 0;
                        }
                    }
                    w = red.getWidth();
                    h = red.getHeight();
                    // 4 - Compose ColorProcessor
                    if (first_mipmap_level_saved < k) {
                        // Skip saving this mipmap level
                        continue;
                    }
                    if (null == alpha) {
                        // 5 - Save as jpeg
                        if (!mmio.save(target_dir + filename, new byte[][] { r, g, b }, w, h, 0.85f)) {
                            Utils.log("Failed to save mipmap for COLOR_RGB, 'alpha = " + alpha + "', level = " + k + " for  patch " + patch);
                            cannot_regenerate.add(patch);
                            break;
                        }
                    } else {
                        if (!mmio.save(target_dir + filename, new byte[][] { r, g, b, a }, w, h, 0.85f)) {
                            Utils.log("Failed to save mipmap for COLOR_RGB, 'alpha = " + alpha + "', level = " + k + " for  patch " + patch);
                            cannot_regenerate.add(patch);
                            break;
                        }
                    }
                } while (// not smaller than 32x32
                w >= 32 && h >= 32);
            } else {
                long t0 = System.currentTimeMillis();
                // Greyscale:
                releaseToFit(w * h * 4 * 10);
                if (Thread.currentThread().isInterrupted())
                    return false;
                final FloatProcessorT2 fp = new FloatProcessorT2((FloatProcessor) ip.convertToFloat());
                if (ImagePlus.GRAY8 == type) {
                    // for 8-bit, the min,max has been applied when going to FloatProcessor
                    // just set it
                    fp.setMinMax(0, 255);
                } else {
                    fp.setMinAndMax(patch.getMin(), patch.getMax());
                }
                // fp.debugMinMax(patch.toString());
                FloatProcessorT2 alpha, outside;
                if (null != alpha_mask) {
                    alpha = new FloatProcessorT2(alpha_mask);
                } else {
                    alpha = null;
                }
                if (null != outside_mask) {
                    outside = new FloatProcessorT2(outside_mask);
                    if (null == alpha) {
                        alpha = outside;
                        alpha_mask = outside_mask;
                    }
                } else {
                    outside = null;
                }
                // the scale level. Proper scale is: 1 / pow(2, k)
                int k = 0;
                do {
                    if (Thread.currentThread().isInterrupted())
                        return false;
                    if (0 != k) {
                        // not doing so at the end because it would add one unnecessary blurring
                        gaussianBlurResizeInHalf(fp);
                        if (null != alpha) {
                            gaussianBlurResizeInHalf(alpha);
                            if (alpha != outside && outside != null) {
                                gaussianBlurResizeInHalf(outside);
                            }
                        }
                    }
                    w = fp.getWidth();
                    h = fp.getHeight();
                    // 1 - check that the target folder for the desired scale exists
                    final String target_dir = getLevelDir(dir_mipmaps, k);
                    if (null == target_dir)
                        break;
                    if (k < first_mipmap_level_saved) {
                        // Skip saving this mipmap level
                        k++;
                        continue;
                    }
                    if (null != alpha) {
                        // If there was no alpha mask, alpha is the outside itself
                        if (!mmio.save(target_dir + filename, new byte[][] { fp.getScaledBytePixels(), P.merge(alpha.getBytePixels(), null == outside ? null : outside.getBytePixels()) }, w, h, 0.85f)) {
                            Utils.log("Failed to save mipmap for GRAY8, 'alpha = " + alpha + "', level = " + k + " for  patch " + patch);
                            cannot_regenerate.add(patch);
                            break;
                        }
                    } else {
                        // 3 - save as 8-bit jpeg
                        if (!mmio.save(target_dir + filename, new byte[][] { fp.getScaledBytePixels() }, w, h, 0.85f)) {
                            Utils.log("Failed to save mipmap for GRAY8, 'alpha = " + alpha + "', level = " + k + " for  patch " + patch);
                            cannot_regenerate.add(patch);
                            break;
                        }
                    }
                    // 4 - prepare values for the next scaled image
                    k++;
                } while (// not smaller than 32x32
                fp.getWidth() >= 32 && fp.getHeight() >= 32);
                long t1 = System.currentTimeMillis();
                System.out.println("MipMaps took " + (t1 - t0));
            }
        } else {
            Utils.log("ERROR: unknown image resizing mode for mipmaps: " + resizing_mode);
        }
        return true;
    } catch (Throwable e) {
        Utils.log("*** ERROR: Can't generate mipmaps for patch " + patch);
        IJError.print(e);
        cannot_regenerate.add(patch);
        return false;
    } finally {
        // flush any cached tiles
        flushMipMaps(patch.getId());
        // flush any cached layer screenshots
        if (null != patch.getLayer()) {
            try {
                patch.getLayer().getParent().removeFromOffscreens(patch.getLayer());
            } catch (Exception e) {
                IJError.print(e);
            }
        }
        // gets executed even when returning from the catch statement or within the try/catch block
        synchronized (gm_lock) {
            regenerating_mipmaps.remove(patch);
        }
        // Has the alpha mask changed?
        if (patch.getAlphaMaskId() != alpha_mask_id) {
            Utils.log2("Alpha mask changed: resubmitting mipmap regeneration for " + patch);
            regenerateMipMaps(patch);
        }
    }
}
Also used : ByteProcessor(ij.process.ByteProcessor) FloatProcessor(ij.process.FloatProcessor) TimeoutException(java.util.concurrent.TimeoutException) ExecutionException(java.util.concurrent.ExecutionException) ImageProcessor(ij.process.ImageProcessor) ColorProcessor(ij.process.ColorProcessor) Patch(ini.trakem2.display.Patch) FloatProcessorT2(ini.trakem2.imaging.FloatProcessorT2)

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