Search in sources :

Example 51 with LayerSet

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

the class AlignTask method transformVectorData.

public static final void transformVectorData(final ReferenceData rd, /* The transformations of patches before alignment. */
final Collection<Displayable> vdata, /* The VectorData instances to transform along with images. */
final LayerSet target_layerset) /* The LayerSet in which the vdata and the transformed images exist. */
{
    final ExecutorService exec = Utils.newFixedThreadPool("AlignTask-transformVectorData");
    try {
        final Collection<Future<?>> fus = new ArrayList<Future<?>>();
        final HashMap<Long, Layer> lidm = new HashMap<Long, Layer>();
        for (final Long lid : rd.src_layer_lids_used) {
            final Layer la = target_layerset.getLayer(lid.longValue());
            if (null == la) {
                Utils.log("ERROR layer with id " + lid + " NOT FOUND in target layerset!");
                continue;
            }
            lidm.put(lid, la);
        }
        for (final Map.Entry<Displayable, Map<Long, TreeMap<Integer, Long>>> ed : rd.underlying.entrySet()) {
            // The VectorData instance to transform
            final Displayable d = ed.getKey();
            // Process Displayables concurrently:
            fus.add(exec.submit(new Runnable() {

                @SuppressWarnings({ "rawtypes", "unchecked" })
                @Override
                public void run() {
                    for (final Map.Entry<Long, TreeMap<Integer, Long>> el : ed.getValue().entrySet()) {
                        // The entry has the id of the layer and the stack-index-ordered list of Patch that intersect VectorData d in that Layer
                        final Layer layer = lidm.get(el.getKey());
                        if (null == layer) {
                            Utils.log("ERROR layer with id " + el.getKey() + " NOT FOUND in target layerset!");
                            continue;
                        }
                        // Utils.log("Editing Displayable " + d + " at layer " + layer);
                        // list of Patch ids affecting VectorData/Displayable d
                        final ArrayList<Long> pids = new ArrayList<Long>(el.getValue().values());
                        // so now Patch ids are sorted from top to bottom
                        Collections.reverse(pids);
                        // The area already processed in the layer
                        final Area used_area = new Area();
                        // The map of areas vs transforms for each area to apply to the VectorData, to its data within the layer only
                        final VectorDataTransform vdt = new VectorDataTransform(layer);
                        // The list of transforms to apply to each VectorData
                        for (final long pid : pids) {
                            // Find the Patch with id 'pid' in Layer 'la' of the target LayerSet:
                            final DBObject ob = layer.findById(pid);
                            if (null == ob || !(ob instanceof Patch)) {
                                Utils.log("ERROR layer with id " + layer.getId() + " DOES NOT CONTAIN a Patch with id " + pid);
                                continue;
                            }
                            final Patch patch = (Patch) ob;
                            // no need to synch, read only from now on
                            final Patch.TransformProperties props = rd.tp.get(pid);
                            if (null == props) {
                                Utils.log("ERROR: could not find any Patch.TransformProperties for patch " + patch);
                                continue;
                            }
                            final Area a = new Area(props.area);
                            a.subtract(used_area);
                            if (M.isEmpty(a)) {
                                // skipping fully occluded Patch
                                continue;
                            }
                            // Accumulate:
                            used_area.add(props.area);
                            // For the remaining area within this Layer, define a transform
                            // Generate a CoordinateTransformList that includes:
                            // 1 - an inverted transform from Patch coords to world coords
                            // 2 - the CoordinateTransform of the Patch, if any
                            // 3 - the AffineTransform of the Patch
                            // 
                            // The idea is to first send the data from world to pixel space of the Patch, using the old transfroms,
                            // and then from pixel space of the Patch to world, using the new transforms.
                            final CoordinateTransformList tlist = new CoordinateTransformList();
                            // 1. Inverse of the old affine: from world into the old patch mipmap
                            final mpicbg.models.AffineModel2D aff_inv = new mpicbg.models.AffineModel2D();
                            try {
                                aff_inv.set(props.at.createInverse());
                            } catch (final NoninvertibleTransformException nite) {
                                Utils.log("ERROR: could not invert the affine transform for Patch " + patch);
                                IJError.print(nite);
                                continue;
                            }
                            tlist.add(aff_inv);
                            // 2. Inverse of the old coordinate transform of the Patch: from old mipmap to pixels in original image
                            if (null != props.ct) {
                                // The props.ct is a CoordinateTransform, not necessarily an InvertibleCoordinateTransform
                                // So the mesh is necessary to ensure the invertibility
                                final mpicbg.trakem2.transform.TransformMesh mesh = new mpicbg.trakem2.transform.TransformMesh(props.ct, props.meshResolution, props.o_width, props.o_height);
                                /* // Apparently not needed; the inverse affine in step 1 took care of it.
								 * // (the affine of step 1 includes the mesh translation)
							Rectangle box = mesh.getBoundingBox();
							AffineModel2D aff = new AffineModel2D();
							aff.set(new AffineTransform(1, 0, 0, 1, box.x, box.y));
							tlist.add(aff);
								 */
                                tlist.add(new InverseICT(mesh));
                            }
                            // 3. New coordinate transform of the Patch: from original image to new mipmap
                            final mpicbg.trakem2.transform.CoordinateTransform ct = patch.getCoordinateTransform();
                            if (null != ct) {
                                tlist.add(ct);
                                final mpicbg.trakem2.transform.TransformMesh mesh = new mpicbg.trakem2.transform.TransformMesh(ct, patch.getMeshResolution(), patch.getOWidth(), patch.getOHeight());
                                // correct for mesh bounds -- Necessary because it comes from the other side, and the removal of the translation here is re-added by the affine in step 4!
                                final Rectangle box = mesh.getBoundingBox();
                                final AffineModel2D aff = new AffineModel2D();
                                aff.set(new AffineTransform(1, 0, 0, 1, -box.x, -box.y));
                                tlist.add(aff);
                            }
                            // 4. New affine transform of the Patch: from mipmap to world
                            final mpicbg.models.AffineModel2D new_aff = new mpicbg.models.AffineModel2D();
                            new_aff.set(patch.getAffineTransform());
                            tlist.add(new_aff);
                            /*
						// TODO Consider caching the tlist for each Patch, or for a few thousand of them maximum.
						//      But it could blow up memory astronomically.

						// The old part:
						final mpicbg.models.InvertibleCoordinateTransformList old = new mpicbg.models.InvertibleCoordinateTransformList();
						if (null != props.ct) {
							mpicbg.trakem2.transform.TransformMesh mesh = new mpicbg.trakem2.transform.TransformMesh(props.ct, props.meshResolution, props.o_width, props.o_height);
							old.add(mesh);
						}
						final mpicbg.models.AffineModel2D old_aff = new mpicbg.models.AffineModel2D();
						old_aff.set(props.at);
						old.add(old_aff);

						tlist.add(new InverseICT(old));

						// The new part:
						final mpicbg.models.AffineModel2D new_aff = new mpicbg.models.AffineModel2D();
						new_aff.set(patch.getAffineTransform());
						tlist.add(new_aff);
						final mpicbg.trakem2.transform.CoordinateTransform ct = patch.getCoordinateTransform();
						if (null != ct) tlist.add(ct);
							 */
                            vdt.add(a, tlist);
                        }
                        // Apply the map of area vs tlist for the data section of d within the layer:
                        try {
                            ((VectorData) d).apply(vdt);
                        } catch (final Exception t) {
                            Utils.log("ERROR transformation failed for " + d + " at layer " + layer);
                            IJError.print(t);
                        }
                    }
                }
            }));
        }
        Utils.wait(fus);
        Display.repaint();
    } finally {
        exec.shutdown();
    }
}
Also used : VectorDataTransform(ini.trakem2.display.VectorDataTransform) HashMap(java.util.HashMap) CoordinateTransformList(mpicbg.trakem2.transform.CoordinateTransformList) ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) DBObject(ini.trakem2.persistence.DBObject) VectorData(ini.trakem2.display.VectorData) AffineModel2D(mpicbg.models.AffineModel2D) CoordinateTransform(mpicbg.trakem2.transform.CoordinateTransform) AbstractAffineModel2D(mpicbg.models.AbstractAffineModel2D) AffineModel2D(mpicbg.models.AffineModel2D) Displayable(ini.trakem2.display.Displayable) TreeMap(java.util.TreeMap) Layer(ini.trakem2.display.Layer) NotEnoughDataPointsException(mpicbg.models.NotEnoughDataPointsException) NoninvertibleModelException(mpicbg.models.NoninvertibleModelException) NoninvertibleTransformException(java.awt.geom.NoninvertibleTransformException) NoninvertibleTransformException(java.awt.geom.NoninvertibleTransformException) Area(java.awt.geom.Area) ExecutorService(java.util.concurrent.ExecutorService) Future(java.util.concurrent.Future) AffineTransform(java.awt.geom.AffineTransform) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap) Patch(ini.trakem2.display.Patch)

Example 52 with LayerSet

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

the class AlignLayersTask method alignLayersLinearlyJob.

public static final void alignLayersLinearlyJob(final LayerSet layerSet, final int first, final int last, final boolean propagateTransform, final Rectangle fov, final Filter<Patch> filter) {
    // will reverse order if necessary
    final List<Layer> layerRange = layerSet.getLayers(first, last);
    final Align.Param p = Align.param.clone();
    // find the first non-empty layer, and remove all empty layers
    Rectangle box = fov;
    for (final Iterator<Layer> it = layerRange.iterator(); it.hasNext(); ) {
        final Layer la = it.next();
        if (!la.contains(Patch.class, true)) {
            it.remove();
            continue;
        }
        if (null == box) {
            // The first layer:
            // Only for visible patches
            box = la.getMinimalBoundingBox(Patch.class, true);
        }
    }
    if (0 == layerRange.size()) {
        Utils.log("All layers in range are empty!");
        return;
    }
    /* do not work if there is only one layer selected */
    if (layerRange.size() < 2)
        return;
    final double scale = Math.min(1.0, Math.min((double) p.sift.maxOctaveSize / (double) box.width, (double) p.sift.maxOctaveSize / (double) box.height));
    p.maxEpsilon *= scale;
    p.identityTolerance *= scale;
    // Utils.log2("scale: " + scale + "  maxOctaveSize: " + p.sift.maxOctaveSize + "  box: " + box.width + "," + box.height);
    final FloatArray2DSIFT sift = new FloatArray2DSIFT(p.sift);
    final SIFT ijSIFT = new SIFT(sift);
    Rectangle box1 = fov;
    Rectangle box2 = fov;
    final Collection<Feature> features1 = new ArrayList<Feature>();
    final Collection<Feature> features2 = new ArrayList<Feature>();
    final List<PointMatch> candidates = new ArrayList<PointMatch>();
    final List<PointMatch> inliers = new ArrayList<PointMatch>();
    final AffineTransform a = new AffineTransform();
    int s = 0;
    for (final Layer layer : layerRange) {
        if (Thread.currentThread().isInterrupted())
            return;
        final long t0 = System.currentTimeMillis();
        features1.clear();
        features1.addAll(features2);
        features2.clear();
        final Rectangle box3 = layer.getMinimalBoundingBox(Patch.class, true);
        // skipping empty layer
        if (box3 == null || (box3.width == 0 && box3.height == 0))
            continue;
        box1 = null == fov ? box2 : fov;
        box2 = null == fov ? box3 : fov;
        final List<Patch> patches = layer.getAll(Patch.class);
        if (null != filter) {
            for (final Iterator<Patch> it = patches.iterator(); it.hasNext(); ) {
                if (!filter.accept(it.next()))
                    it.remove();
            }
        }
        final ImageProcessor flatImage = layer.getProject().getLoader().getFlatImage(layer, box2, scale, 0xffffffff, ImagePlus.GRAY8, Patch.class, patches, true).getProcessor();
        ijSIFT.extractFeatures(flatImage, features2);
        IJ.log(features2.size() + " features extracted in layer \"" + layer.getTitle() + "\" (took " + (System.currentTimeMillis() - t0) + " ms).");
        if (features1.size() > 0) {
            final long t1 = System.currentTimeMillis();
            candidates.clear();
            FeatureTransform.matchFeatures(features2, features1, candidates, p.rod);
            final AbstractAffineModel2D<?> model;
            switch(p.expectedModelIndex) {
                case 0:
                    model = new TranslationModel2D();
                    break;
                case 1:
                    model = new RigidModel2D();
                    break;
                case 2:
                    model = new SimilarityModel2D();
                    break;
                case 3:
                    model = new AffineModel2D();
                    break;
                default:
                    return;
            }
            final AbstractAffineModel2D<?> desiredModel;
            switch(p.desiredModelIndex) {
                case 0:
                    desiredModel = new TranslationModel2D();
                    break;
                case 1:
                    desiredModel = new RigidModel2D();
                    break;
                case 2:
                    desiredModel = new SimilarityModel2D();
                    break;
                case 3:
                    desiredModel = new AffineModel2D();
                    break;
                default:
                    return;
            }
            boolean modelFound;
            boolean again = false;
            try {
                do {
                    again = false;
                    modelFound = model.filterRansac(candidates, inliers, 1000, p.maxEpsilon, p.minInlierRatio, p.minNumInliers, 3);
                    if (modelFound && p.rejectIdentity) {
                        final ArrayList<Point> points = new ArrayList<Point>();
                        PointMatch.sourcePoints(inliers, points);
                        if (Transforms.isIdentity(model, points, p.identityTolerance)) {
                            IJ.log("Identity transform for " + inliers.size() + " matches rejected.");
                            candidates.removeAll(inliers);
                            inliers.clear();
                            again = true;
                        }
                    }
                } while (again);
                if (modelFound)
                    desiredModel.fit(inliers);
            } catch (final NotEnoughDataPointsException e) {
                modelFound = false;
            } catch (final IllDefinedDataPointsException e) {
                modelFound = false;
            }
            if (Thread.currentThread().isInterrupted())
                return;
            if (modelFound) {
                IJ.log("Model found for layer \"" + layer.getTitle() + "\" and its predecessor:\n  correspondences  " + inliers.size() + " of " + candidates.size() + "\n  average residual error  " + (model.getCost() / scale) + " px\n  took " + (System.currentTimeMillis() - t1) + " ms");
                final AffineTransform b = new AffineTransform();
                b.translate(box1.x, box1.y);
                b.scale(1.0f / scale, 1.0f / scale);
                b.concatenate(desiredModel.createAffine());
                b.scale(scale, scale);
                b.translate(-box2.x, -box2.y);
                a.concatenate(b);
                AlignTask.transformPatchesAndVectorData(patches, a);
                Display.repaint(layer);
            } else {
                IJ.log("No model found for layer \"" + layer.getTitle() + "\" and its predecessor:\n  correspondence candidates  " + candidates.size() + "\n  took " + (System.currentTimeMillis() - s) + " ms");
                a.setToIdentity();
            }
        }
        IJ.showProgress(++s, layerRange.size());
    }
    if (Thread.currentThread().isInterrupted())
        return;
    if (propagateTransform) {
        if (last > first && last < layerSet.size() - 2)
            for (final Layer la : layerSet.getLayers(last + 1, layerSet.size() - 1)) {
                if (Thread.currentThread().isInterrupted())
                    return;
                AlignTask.transformPatchesAndVectorData(la, a);
            }
        else if (first > last && last > 0)
            for (final Layer la : layerSet.getLayers(0, last - 1)) {
                if (Thread.currentThread().isInterrupted())
                    return;
                AlignTask.transformPatchesAndVectorData(la, a);
            }
    }
}
Also used : NotEnoughDataPointsException(mpicbg.models.NotEnoughDataPointsException) SIFT(mpicbg.ij.SIFT) FloatArray2DSIFT(mpicbg.imagefeatures.FloatArray2DSIFT) Rectangle(java.awt.Rectangle) ArrayList(java.util.ArrayList) Feature(mpicbg.imagefeatures.Feature) ImageProcessor(ij.process.ImageProcessor) RigidModel2D(mpicbg.trakem2.transform.RigidModel2D) AbstractAffineModel2D(mpicbg.models.AbstractAffineModel2D) AffineModel2D(mpicbg.models.AffineModel2D) SimilarityModel2D(mpicbg.models.SimilarityModel2D) IllDefinedDataPointsException(mpicbg.models.IllDefinedDataPointsException) Point(mpicbg.models.Point) Layer(ini.trakem2.display.Layer) Point(mpicbg.models.Point) FloatArray2DSIFT(mpicbg.imagefeatures.FloatArray2DSIFT) PointMatch(mpicbg.models.PointMatch) AffineTransform(java.awt.geom.AffineTransform) TranslationModel2D(mpicbg.trakem2.transform.TranslationModel2D) Patch(ini.trakem2.display.Patch)

Example 53 with LayerSet

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

the class ElasticLayerAlignment method exec.

/**
 * Stateful.  Changing the parameters of this instance.  Do not use in parallel.
 *
 * @param layerSet
 * @param firstIn
 * @param lastIn
 * @param propagateTransformBefore
 * @param propagateTransformAfter
 * @param fov
 * @param filter
 */
public final void exec(final LayerSet layerSet, final int firstIn, final int lastIn, final int ref, final boolean propagateTransformBefore, final boolean propagateTransformAfter, final Rectangle fov, final Filter<Patch> filter) throws Exception {
    final int first = Math.min(firstIn, lastIn);
    final int last = Math.max(firstIn, lastIn);
    /* always first index first despite the method would return inverse order if last > first */
    final List<Layer> layerRange = layerSet.getLayers(first, last);
    final HashSet<Layer> fixedLayers = new HashSet<Layer>();
    if (ref - firstIn >= 0)
        fixedLayers.add(layerRange.get(ref - firstIn));
    Utils.log(layerRange.size() + "");
    exec(layerSet.getProject(), layerRange, fixedLayers, propagateTransformBefore, propagateTransformAfter, fov, filter);
}
Also used : Layer(ini.trakem2.display.Layer) Point(mpicbg.models.Point) HashSet(java.util.HashSet)

Example 54 with LayerSet

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

the class MatchIntensities method invoke.

@Override
public Object invoke(final Object... params) {
    if (!setup(params))
        return null;
    final Layer layer = currentLayer(params);
    final GenericDialog gd = new GenericDialog("Match intensities");
    Utils.addLayerRangeChoices(layer, gd);
    gd.addMessage("Layer range :");
    gd.addNumericField("scale : ", scale > 0 ? scale : suggestScale(layerset.getLayers()), 3, 6, "");
    gd.addNumericField("coefficient resolution : ", numCoefficients, 0, 6, "");
    gd.addNumericField("test_maximally :", radius, 0, 6, "layers");
    gd.addMessage("Optimizer :");
    gd.addNumericField("iterations :", iterations, 0, 6, "");
    gd.addNumericField("scale_regularization :", lambda1, 2, 6, "");
    gd.addNumericField("translation_regularization :", lambda2, 2, 6, "");
    gd.addNumericField("smoothness_regularization :", neighborWeight, 2, 6, "");
    gd.showDialog();
    if (gd.wasCanceled())
        return null;
    final List<Layer> layers = layerset.getLayers().subList(gd.getNextChoiceIndex(), gd.getNextChoiceIndex() + 1);
    System.out.println(layers.size());
    scale = gd.getNextNumber();
    numCoefficients = (int) gd.getNextNumber();
    radius = (int) gd.getNextNumber();
    iterations = (int) gd.getNextNumber();
    lambda1 = gd.getNextNumber();
    lambda2 = gd.getNextNumber();
    neighborWeight = gd.getNextNumber();
    try {
        run(layers, radius, scale, numCoefficients, lambda1, lambda2, neighborWeight, getRoi(layerset));
    } catch (final InterruptedException e) {
        Utils.log("Match intensities interrupted.");
        e.printStackTrace(System.out);
    } catch (final ExecutionException e) {
        Utils.log("Match intenities ExecutiuonException occurred:");
        e.printStackTrace(System.out);
    }
    return null;
}
Also used : GenericDialog(ij.gui.GenericDialog) ExecutionException(java.util.concurrent.ExecutionException) Layer(ini.trakem2.display.Layer)

Example 55 with LayerSet

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

the class RegularizedAffineLayerAlignment method exec.

/**
 * Stateful.  Changing the parameters of this instance.  Do not use in parallel.
 *
 * @param layerSet
 * @param firstIn
 * @param lastIn
 * @param ref
 * @param propagateTransformBefore
 * @param propagateTransformAfter
 * @param fov
 * @param filter
 */
public final void exec(final LayerSet layerSet, final int firstIn, final int lastIn, final int ref, final boolean propagateTransformBefore, final boolean propagateTransformAfter, final Rectangle fov, final Filter<Patch> filter) throws Exception {
    final int first = Math.min(firstIn, lastIn);
    final int last = Math.max(firstIn, lastIn);
    /* always first index first despite the method would return inverse order if last > first */
    final List<Layer> layerRange = layerSet.getLayers(first, last);
    final HashSet<Layer> fixedLayers = new HashSet<Layer>();
    if (ref - first >= 0)
        fixedLayers.add(layerRange.get(ref - first));
    Utils.log(layerRange.size() + "");
    exec(layerRange, fixedLayers, propagateTransformBefore, propagateTransformAfter, fov, filter);
}
Also used : Layer(ini.trakem2.display.Layer) Point(mpicbg.models.Point) HashSet(java.util.HashSet)

Aggregations

ArrayList (java.util.ArrayList)24 Layer (ini.trakem2.display.Layer)22 LayerSet (ini.trakem2.display.LayerSet)20 HashMap (java.util.HashMap)20 HashSet (java.util.HashSet)19 Rectangle (java.awt.Rectangle)14 Patch (ini.trakem2.display.Patch)13 ImagePlus (ij.ImagePlus)11 GenericDialog (ij.gui.GenericDialog)11 ProjectThing (ini.trakem2.tree.ProjectThing)11 AffineTransform (java.awt.geom.AffineTransform)11 Map (java.util.Map)11 Future (java.util.concurrent.Future)11 Displayable (ini.trakem2.display.Displayable)10 ZDisplayable (ini.trakem2.display.ZDisplayable)10 Area (java.awt.geom.Area)10 Worker (ini.trakem2.utils.Worker)9 Point (java.awt.Point)9 TreeMap (java.util.TreeMap)9 DBObject (ini.trakem2.persistence.DBObject)8