Search in sources :

Example 21 with Stack

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

the class AreaList method getStack.

/**
 * Returns a stack of images representing the pixel data of this LayerSet inside this AreaList.
 */
public ImagePlus getStack(final int type, final double scale) {
    final ImageProcessor ref_ip = Utils.createProcessor(type, 2, 2);
    if (null == ref_ip) {
        Utils.log("AreaList.getStack: Unknown type " + type);
        return null;
    }
    final Rectangle b = getBoundingBox();
    final int w = (int) (0.5 + b.width * scale);
    final int h = (int) (0.5 + b.height * scale);
    final ImageStack stack = new ImageStack(w, h);
    for (final Layer la : getLayerRange()) {
        final Area area = getArea(la);
        final double z = layer.getZ();
        project.getLoader().releaseToFit(w * h * 10);
        final ImageProcessor ip = ref_ip.createProcessor(w, h);
        if (null == area) {
            stack.addSlice(Double.toString(z), ip);
            continue;
        }
        // Create a ROI from the area at Layer la:
        final AffineTransform aff = getAffineTransformCopy();
        aff.translate(-b.x, -b.y);
        aff.scale(scale, scale);
        final ShapeRoi roi = new ShapeRoi(area.createTransformedArea(aff));
        // Create a cropped snapshot of the images at Layer la under the area:
        final ImageProcessor flat = Patch.makeFlatImage(type, la, b, scale, la.getAll(Patch.class), Color.black);
        flat.setRoi(roi);
        final Rectangle rb = roi.getBounds();
        ip.insert(flat.crop(), rb.x, rb.y);
        // Clear the outside
        final ImagePlus bimp = new ImagePlus("", ip);
        bimp.setRoi(roi);
        ip.setValue(0);
        ip.setBackgroundValue(0);
        IJ.run(bimp, "Clear Outside", "");
        stack.addSlice(Double.toString(z), ip);
    }
    final ImagePlus imp = new ImagePlus("AreaList stack for " + this, stack);
    imp.setCalibration(layer_set.getCalibrationCopy());
    return imp;
}
Also used : ImageProcessor(ij.process.ImageProcessor) Area(java.awt.geom.Area) ShapeRoi(ij.gui.ShapeRoi) ImageStack(ij.ImageStack) Rectangle(java.awt.Rectangle) AffineTransform(java.awt.geom.AffineTransform) ImagePlus(ij.ImagePlus) Point(java.awt.Point) USHORTPaint(ini.trakem2.display.paint.USHORTPaint)

Example 22 with Stack

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

the class Project method newFSProject.

public static Project newFSProject(String arg, TemplateThing template_root, String storage_folder, boolean autocreate_one_layer) {
    if (Utils.wrongImageJVersion())
        return null;
    FSLoader loader = null;
    try {
        String dir_project = storage_folder;
        if (null == dir_project || !new File(dir_project).isDirectory()) {
            DirectoryChooser dc = new DirectoryChooser("Select storage folder");
            dir_project = dc.getDirectory();
            // user cancelled dialog
            if (null == dir_project)
                return null;
            if (!Loader.canReadAndWriteTo(dir_project)) {
                Utils.showMessage("Can't read/write to the selected storage folder.\nPlease check folder permissions.");
                return null;
            }
            if (IJ.isWindows())
                dir_project = dir_project.replace('\\', '/');
        }
        loader = new FSLoader(dir_project);
        Project project = createNewProject(loader, !("blank".equals(arg) || "amira".equals(arg)), template_root);
        // help the helpless users:
        if (autocreate_one_layer && null != project && ControlWindow.isGUIEnabled()) {
            Utils.log2("Creating automatic Display.");
            // add a default layer
            Layer layer = new Layer(project, 0, 1, project.layer_set);
            project.layer_set.add(layer);
            project.layer_tree.addLayer(project.layer_set, layer);
            layer.recreateBuckets();
            Display.createDisplay(project, layer);
        }
        try {
            // waiting cheaply for asynchronous swing calls
            Thread.sleep(200);
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        }
        if ("amira".equals(arg) || "stack".equals(arg)) {
            // forks into a task thread
            loader.importStack(project.layer_set.getLayer(0), null, true);
        }
        project.restartAutosaving();
        return project;
    } catch (Exception e) {
        IJError.print(e);
        if (null != loader)
            loader.destroy();
    }
    return null;
}
Also used : FSLoader(ini.trakem2.persistence.FSLoader) JarFile(java.util.jar.JarFile) File(java.io.File) Layer(ini.trakem2.display.Layer) DirectoryChooser(ij.io.DirectoryChooser)

Example 23 with Stack

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

the class AreaList method exportAsLabels.

/**
 * Export all given AreaLists as one per pixel value, what is called a "labels" file; a file dialog is offered to save the image as a tiff stack.
 */
public static void exportAsLabels(final List<Displayable> listToPaint, final ij.gui.Roi roi, final float scale, int first_layer, int last_layer, final boolean visible_only, final boolean to_file, final boolean as_amira_labels) {
    // survive everything:
    if (null == listToPaint || 0 == listToPaint.size()) {
        Utils.log("Null or empty list.");
        return;
    }
    if (scale < 0 || scale > 1) {
        Utils.log("Improper scale value. Must be 0 < scale <= 1");
        return;
    }
    // Select the subset to paint
    final ArrayList<AreaList> list = new ArrayList<AreaList>();
    for (final Displayable d : listToPaint) {
        if (visible_only && !d.isVisible())
            continue;
        if (d instanceof AreaList)
            list.add((AreaList) d);
    }
    Utils.log2("exportAsLabels: list.size() is " + list.size());
    // Current AmiraMeshEncoder supports ByteProcessor only: 256 labels max, including background at zero.
    if (as_amira_labels && list.size() > 255) {
        Utils.log("Saving ONLY first 255 AreaLists!\nDiscarded:");
        final StringBuilder sb = new StringBuilder();
        for (final Displayable d : list.subList(255, list.size())) {
            sb.append("    ").append(d.getProject().getShortMeaningfulTitle(d)).append('\n');
        }
        Utils.log(sb.toString());
        final ArrayList<AreaList> li = new ArrayList<AreaList>(list);
        list.clear();
        list.addAll(li.subList(0, 255));
    }
    String path = null;
    if (to_file) {
        final String ext = as_amira_labels ? ".am" : ".tif";
        final File f = Utils.chooseFile("labels", ext);
        if (null == f)
            return;
        path = f.getAbsolutePath().replace('\\', '/');
    }
    final LayerSet layer_set = list.get(0).getLayerSet();
    if (first_layer > last_layer) {
        final int tmp = first_layer;
        first_layer = last_layer;
        last_layer = tmp;
        if (first_layer < 0)
            first_layer = 0;
        if (last_layer >= layer_set.size())
            last_layer = layer_set.size() - 1;
    }
    // Create image according to roi and scale
    final int width, height;
    final Rectangle broi;
    if (null == roi) {
        broi = null;
        width = (int) (layer_set.getLayerWidth() * scale);
        height = (int) (layer_set.getLayerHeight() * scale);
    } else {
        broi = roi.getBounds();
        width = (int) (broi.width * scale);
        height = (int) (broi.height * scale);
    }
    // Compute highest label value, which affects of course the stack image type
    final TreeSet<Integer> label_values = new TreeSet<Integer>();
    for (final Displayable d : list) {
        final String label = d.getProperty("label");
        if (null != label)
            label_values.add(Integer.parseInt(label));
    }
    int lowest = 0, highest = 0;
    if (label_values.size() > 0) {
        lowest = label_values.first();
        highest = label_values.last();
    }
    final int n_non_labeled = list.size() - label_values.size();
    final int max_label_value = highest + n_non_labeled;
    int type_ = ImagePlus.GRAY8;
    if (max_label_value > 255) {
        type_ = ImagePlus.GRAY16;
        if (max_label_value > 65535) {
            type_ = ImagePlus.GRAY32;
        }
    }
    final int type = type_;
    final ImageStack stack = new ImageStack(width, height);
    final Calibration cal = layer_set.getCalibration();
    String amira_params = null;
    if (as_amira_labels) {
        final StringBuilder sb = new StringBuilder("CoordType \"uniform\"\nMaterials {\nExterior {\n Id 0,\nColor 0 0 0\n}\n");
        final float[] c = new float[3];
        int value = 0;
        for (final Displayable d : list) {
            // 0 is background
            value++;
            d.getColor().getRGBColorComponents(c);
            String s = d.getProject().getShortMeaningfulTitle(d);
            s = s.replace('-', '_').replaceAll(" #", " id");
            sb.append(Utils.makeValidIdentifier(s)).append(" {\n").append("Id ").append(value).append(",\n").append("Color ").append(c[0]).append(' ').append(c[1]).append(' ').append(c[2]).append("\n}\n");
        }
        sb.append("}\n");
        amira_params = sb.toString();
    }
    final float len = last_layer - first_layer + 1;
    // Assign labels
    final HashMap<AreaList, Integer> labels = new HashMap<AreaList, Integer>();
    for (final AreaList d : list) {
        final String slabel = d.getProperty("label");
        int label;
        if (null != slabel) {
            label = Integer.parseInt(slabel);
        } else {
            // 0 is background
            label = (++highest);
        }
        labels.put(d, label);
    }
    final ExecutorService exec = Utils.newFixedThreadPool("labels");
    final Map<Integer, ImageProcessor> slices = Collections.synchronizedMap(new TreeMap<Integer, ImageProcessor>());
    final List<Future<?>> fus = new ArrayList<Future<?>>();
    final List<Layer> layers = layer_set.getLayers().subList(first_layer, last_layer + 1);
    for (int k = 0; k < layers.size(); k++) {
        final Layer la = layers.get(k);
        final int slice = k;
        fus.add(exec.submit(new Runnable() {

            @Override
            public void run() {
                Utils.showProgress(slice / len);
                final ImageProcessor ip;
                if (ImagePlus.GRAY8 == type) {
                    final BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
                    final Graphics2D g = bi.createGraphics();
                    for (final AreaList ali : list) {
                        final Area area = ali.getArea(la);
                        if (null == area || area.isEmpty())
                            continue;
                        // Transform: the scale and the roi
                        final AffineTransform aff = new AffineTransform();
                        /* 3 - To scale: */
                        if (1 != scale)
                            aff.scale(scale, scale);
                        /* 2 - To roi coordinates: */
                        if (null != broi)
                            aff.translate(-broi.x, -broi.y);
                        /* 1 - To world coordinates: */
                        aff.concatenate(ali.at);
                        g.setTransform(aff);
                        final int label = labels.get(ali);
                        g.setColor(new Color(label, label, label));
                        g.fill(area);
                    }
                    g.dispose();
                    ip = new ByteProcessor(bi);
                    bi.flush();
                } else if (ImagePlus.GRAY16 == type) {
                    final USHORTPaint paint = new USHORTPaint((short) 0);
                    final BufferedImage bi = new BufferedImage(paint.getComponentColorModel(), paint.getComponentColorModel().createCompatibleWritableRaster(width, height), false, null);
                    final Graphics2D g = bi.createGraphics();
                    // final ColorSpace ugray = ColorSpace.getInstance(ColorSpace.CS_GRAY);
                    int painted = 0;
                    for (final AreaList ali : list) {
                        final Area area = ali.getArea(la);
                        if (null == area || area.isEmpty())
                            continue;
                        // Transform: the scale and the roi
                        final AffineTransform aff = new AffineTransform();
                        /* 3 - To scale: */
                        if (1 != scale)
                            aff.scale(scale, scale);
                        /* 2 - To roi coordinates: */
                        if (null != broi)
                            aff.translate(-broi.x, -broi.y);
                        /* 1 - To world coordinates: */
                        aff.concatenate(ali.at);
                        // Fill
                        g.setTransform(aff);
                        // The color doesn't work: paints in a stretched 8-bit mode
                        // g.setColor(new Color(ugray, new float[]{((float)labels.get(d)) / range}, 1));
                        Utils.log2("value: " + labels.get(ali).shortValue());
                        paint.setValue(labels.get(ali).shortValue());
                        g.setPaint(paint);
                        // .createTransformedArea(aff));
                        g.fill(area);
                        painted += 1;
                    }
                    g.dispose();
                    ip = new ShortProcessor(bi);
                    bi.flush();
                    Utils.log2("painted: " + painted);
                } else {
                    // Option 1: could use the same as above, but shifted by 65536, so that 65537 is 1, 65538 is 2, etc.
                    // and keep doing it until no more need to be shifted.
                    // The PROBLEM: cannot keep the order without complicated gymnastics to remember
                    // which label in which image has to be merged to the final image, which prevent
                    // a simple one-pass blitter.
                    // 
                    // Option 2: paint each arealist, extract the image, use it as a mask for filling:
                    final FloatProcessor fp = new FloatProcessor(width, height);
                    final float[] fpix = (float[]) fp.getPixels();
                    ip = fp;
                    final BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
                    final Graphics2D gbi = bi.createGraphics();
                    for (final AreaList ali : list) {
                        final Area area = ali.getArea(la);
                        if (null == area || area.isEmpty()) {
                            continue;
                        }
                        // Transform: the scale and the roi
                        // reverse order of transformations:
                        final AffineTransform aff = new AffineTransform();
                        /* 3 - To scale: */
                        if (1 != scale)
                            aff.scale(scale, scale);
                        /* 2 - To ROI coordinates: */
                        if (null != broi)
                            aff.translate(-broi.x, -broi.y);
                        /* 1 - To world coordinates: */
                        aff.concatenate(ali.at);
                        final Area s = area.createTransformedArea(aff);
                        final Rectangle sBounds = s.getBounds();
                        // Need to paint at all?
                        if (0 == sBounds.width || 0 == sBounds.height || !sBounds.intersects(0, 0, width, height))
                            continue;
                        // Paint shape
                        gbi.setColor(Color.white);
                        gbi.fill(s);
                        // Read out painted region
                        final int x0 = Math.max(0, sBounds.x);
                        final int y0 = Math.max(0, sBounds.y);
                        final int xN = Math.min(width, sBounds.x + sBounds.width);
                        final int yN = Math.min(height, sBounds.y + sBounds.height);
                        // Get the array
                        final byte[] bpix = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData();
                        final float value = labels.get(ali);
                        // For every non-black pixel, set a 'value' pixel in the FloatProcessor
                        for (int y = y0; y < yN; ++y) {
                            for (int x = x0; x < xN; ++x) {
                                final int pos = y * width + x;
                                // black
                                if (0 == bpix[pos])
                                    continue;
                                fpix[pos] = value;
                            }
                        }
                        // Clear image region
                        gbi.setColor(Color.black);
                        gbi.fill(s);
                    }
                    gbi.dispose();
                    bi.flush();
                }
                slices.put(slice, ip);
            }
        }));
    }
    Utils.wait(fus);
    exec.shutdownNow();
    for (final Map.Entry<Integer, ImageProcessor> e : slices.entrySet()) {
        final Layer la = layers.get(e.getKey());
        stack.addSlice(la.getZ() * cal.pixelWidth + "", e.getValue());
        if (ImagePlus.GRAY8 != type) {
            e.getValue().setMinAndMax(lowest, highest);
        }
    }
    Utils.showProgress(1);
    // Save via file dialog:
    final ImagePlus imp = new ImagePlus("Labels", stack);
    if (as_amira_labels)
        imp.setProperty("Info", amira_params);
    imp.setCalibration(layer_set.getCalibrationCopy());
    if (to_file) {
        if (as_amira_labels) {
            final AmiraMeshEncoder ame = new AmiraMeshEncoder(path);
            if (!ame.open()) {
                Utils.log("Could not write to file " + path);
                return;
            }
            if (!ame.write(imp)) {
                Utils.log("Error in writing Amira file!");
                return;
            }
        } else {
            new FileSaver(imp).saveAsTiff(path);
        }
    } else
        imp.show();
}
Also used : ByteProcessor(ij.process.ByteProcessor) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) BufferedImage(java.awt.image.BufferedImage) ImageProcessor(ij.process.ImageProcessor) USHORTPaint(ini.trakem2.display.paint.USHORTPaint) FileSaver(ij.io.FileSaver) TreeSet(java.util.TreeSet) ImageStack(ij.ImageStack) FloatProcessor(ij.process.FloatProcessor) Color(java.awt.Color) Calibration(ij.measure.Calibration) ImagePlus(ij.ImagePlus) Point(java.awt.Point) USHORTPaint(ini.trakem2.display.paint.USHORTPaint) Graphics2D(java.awt.Graphics2D) ShortProcessor(ij.process.ShortProcessor) Area(java.awt.geom.Area) ExecutorService(java.util.concurrent.ExecutorService) AmiraMeshEncoder(amira.AmiraMeshEncoder) Future(java.util.concurrent.Future) AffineTransform(java.awt.geom.AffineTransform) File(java.io.File) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap)

Example 24 with Stack

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

the class Loader method createLazyFlyThrough.

/**
 * Each slice is generated on demand, one slice per Region instance.
 */
public <I> ImagePlus createLazyFlyThrough(final List<? extends Region<I>> regions, final double magnification, final int type, final Displayable active) {
    final Region<I> first = regions.get(0);
    final int w = (int) (first.r.width * magnification), h = (int) (first.r.height * magnification);
    final LazyVirtualStack stack = new LazyVirtualStack(w, h, regions.size());
    for (final Region<I> r : regions) {
        stack.addSlice(new Callable<ImageProcessor>() {

            @Override
            public ImageProcessor call() {
                return getFlatImage(r.layer, r.r, magnification, 0xffffffff, type, Displayable.class, null, true, Color.black, active).getProcessor();
            }
        });
    }
    return new ImagePlus("Fly-Through", stack);
}
Also used : ImageProcessor(ij.process.ImageProcessor) LazyVirtualStack(ini.trakem2.imaging.LazyVirtualStack) ImagePlus(ij.ImagePlus)

Example 25 with Stack

use of ini.trakem2.display.Stack 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)

Aggregations

ImagePlus (ij.ImagePlus)21 Layer (ini.trakem2.display.Layer)16 ArrayList (java.util.ArrayList)15 Rectangle (java.awt.Rectangle)13 Patch (ini.trakem2.display.Patch)12 ImageStack (ij.ImageStack)11 AffineTransform (java.awt.geom.AffineTransform)11 ImageProcessor (ij.process.ImageProcessor)8 Area (java.awt.geom.Area)8 File (java.io.File)8 HashMap (java.util.HashMap)8 TreeMap (java.util.TreeMap)8 Point (java.awt.Point)7 HashSet (java.util.HashSet)7 Map (java.util.Map)7 GenericDialog (ij.gui.GenericDialog)6 Calibration (ij.measure.Calibration)6 Displayable (ini.trakem2.display.Displayable)6 Worker (ini.trakem2.utils.Worker)6 DirectoryChooser (ij.io.DirectoryChooser)5