Search in sources :

Example 6 with AbstractAffineModel2D

use of mpicbg.models.AbstractAffineModel2D in project TrakEM2 by trakem2.

the class ManualAlignMode method apply.

@Override
public boolean apply() {
    // Check there's more than one layer
    if (m.size() < 2) {
        Utils.showMessage("Need more than one layer to align!");
        return false;
    }
    // Check that the current layer is one of the layers with landmarks.
    // Will be used as reference
    final Layer ref_layer = display.getLayer();
    if (null == m.get(ref_layer)) {
        Utils.showMessage("Please scroll to a layer with landmarks,\nto be used as reference.");
        return false;
    }
    // Check that all layers have the same number of landmarks
    int n_landmarks = -1;
    for (final Map.Entry<Layer, Landmarks> e : m.entrySet()) {
        final Landmarks lm = e.getValue();
        if (-1 == n_landmarks) {
            n_landmarks = lm.points.size();
            continue;
        }
        if (n_landmarks != lm.points.size()) {
            Utils.showMessage("Can't apply: there are different amounts of landmarks per layer.\nSee the log window.");
            for (final Map.Entry<Layer, Landmarks> ee : m.entrySet()) {
                Utils.log(ee.getValue().points.size() + " landmarks in layer " + ee.getKey());
            }
            return false;
        }
    }
    // Sort Layers by Z
    final TreeMap<Layer, Landmarks> sorted = new TreeMap<Layer, Landmarks>(new Comparator<Layer>() {

        @Override
        public boolean equals(final Object ob) {
            return this == ob;
        }

        @Override
        public int compare(final Layer l1, final Layer l2) {
            // Ascending order
            final double dz = l1.getZ() - l2.getZ();
            if (dz < 0)
                return -1;
            else if (dz > 0)
                return 1;
            else
                return 0;
        }
    });
    sorted.putAll(m);
    int iref = 0;
    for (final Layer la : sorted.keySet()) {
        if (la != ref_layer)
            iref++;
        else
            break;
    }
    // Ok, now ask for a model
    final GenericDialog gd = new GenericDialog("Model");
    gd.addChoice("Model:", Align.Param.modelStrings, Align.Param.modelStrings[1]);
    gd.addCheckbox("Propagate to first layer", 0 != iref);
    ((Component) gd.getCheckboxes().get(0)).setEnabled(0 != iref);
    gd.addCheckbox("Propagate to last layer", sorted.size() - 1 != iref);
    ((Component) gd.getCheckboxes().get(1)).setEnabled(sorted.size() - 1 != iref);
    gd.showDialog();
    if (gd.wasCanceled())
        return false;
    final int model_index = gd.getNextChoiceIndex();
    final boolean propagate_to_first = gd.getNextBoolean();
    final boolean propagate_to_last = gd.getNextBoolean();
    int min;
    // Create a model as desired
    final AbstractAffineModel2D<?> model;
    switch(model_index) {
        case 0:
            min = 1;
            model = new TranslationModel2D();
            break;
        case 1:
            min = 2;
            model = new RigidModel2D();
            break;
        case 2:
            min = 2;
            model = new SimilarityModel2D();
            break;
        case 3:
            min = 3;
            model = new AffineModel2D();
            break;
        default:
            Utils.log("Unknown model index!");
            return false;
    }
    if (n_landmarks < min) {
        Utils.showMessage("Need at least " + min + " landmarks for a " + Align.Param.modelStrings[model_index] + " model");
        return false;
    }
    Bureaucrat.createAndStart(new Worker.Task("Aligning layers with landmarks") {

        @Override
        public void exec() {
            // Find layers with landmarks, in increasing Z.
            // Match in pairs.
            // So, get two submaps: from ref_layer to first, and from ref_layer to last
            // strictly lower Z than ref_layer
            final SortedMap<Layer, Landmarks> first_chunk_ = new TreeMap<Layer, Landmarks>(sorted.headMap(ref_layer));
            // .. so add ref_layer
            first_chunk_.put(ref_layer, m.get(ref_layer));
            // equal or larger Z than ref_layer
            final SortedMap<Layer, Landmarks> second_chunk = sorted.tailMap(ref_layer);
            final SortedMap<Layer, Landmarks> first_chunk;
            // Reverse order of first_chunk
            if (first_chunk_.size() > 1) {
                final SortedMap<Layer, Landmarks> fc = new TreeMap<Layer, Landmarks>(new Comparator<Layer>() {

                    @Override
                    public boolean equals(final Object ob) {
                        return this == ob;
                    }

                    @Override
                    public int compare(final Layer l1, final Layer l2) {
                        // Descending order
                        final double dz = l2.getZ() - l1.getZ();
                        if (dz < 0)
                            return -1;
                        else if (dz > 0)
                            return 1;
                        else
                            return 0;
                    }
                });
                fc.putAll(first_chunk_);
                first_chunk = fc;
            } else {
                first_chunk = first_chunk_;
            }
            final LayerSet ls = ref_layer.getParent();
            final Collection<Layer> affected_layers = new HashSet<Layer>(m.keySet());
            // Gather all Patch instances that will be affected
            final ArrayList<Patch> patches = new ArrayList<Patch>();
            for (final Layer la : m.keySet()) patches.addAll(la.getAll(Patch.class));
            if (propagate_to_first && first_chunk.size() > 1) {
                final Collection<Layer> affected = ls.getLayers().subList(0, ls.indexOf(first_chunk.lastKey()));
                for (final Layer la : affected) {
                    patches.addAll(la.getAll(Patch.class));
                }
                affected_layers.addAll(affected);
            }
            if (propagate_to_last && second_chunk.size() > 1) {
                final Collection<Layer> affected = ls.getLayers().subList(ls.indexOf(second_chunk.lastKey()) + 1, ls.size());
                for (final Layer la : affected) {
                    patches.addAll(la.getAll(Patch.class));
                }
            }
            // Transform segmentations along with patches
            AlignTask.transformPatchesAndVectorData(patches, new Runnable() {

                @Override
                public void run() {
                    // Apply!
                    // TODO: when adding non-linear transforms, use this single line for undo instead of all below:
                    // (these transforms may be non-linear as well, which alter mipmaps.)
                    // ls.addTransformStepWithData(affected_layers);
                    // Setup undo:
                    // Find all images in the range of affected layers,
                    // plus all Displayable of those layers (but Patch instances in a separate DoTransforms step,
                    // to avoid adding a "data" undo for them, which would recreate mipmaps when undone).
                    // plus all ZDisplayable that paint in those layers
                    final HashSet<Displayable> ds = new HashSet<Displayable>();
                    final ArrayList<Displayable> patches = new ArrayList<Displayable>();
                    for (final Layer layer : affected_layers) {
                        for (final Displayable d : layer.getDisplayables()) {
                            if (d.getClass() == Patch.class) {
                                patches.add(d);
                            } else {
                                ds.add(d);
                            }
                        }
                    }
                    for (final ZDisplayable zd : ls.getZDisplayables()) {
                        for (final Layer layer : affected_layers) {
                            if (zd.paintsAt(layer)) {
                                ds.add((Displayable) zd);
                                break;
                            }
                        }
                    }
                    if (ds.size() > 0) {
                        final Displayable.DoEdits step = ls.addTransformStepWithData(ds);
                        if (patches.size() > 0) {
                            final ArrayList<DoStep> a = new ArrayList<DoStep>();
                            a.add(new Displayable.DoTransforms().addAll(patches));
                            step.addDependents(a);
                        }
                    }
                    if (first_chunk.size() > 1) {
                        final AffineTransform aff = align(first_chunk, model);
                        if (propagate_to_first) {
                            for (final Layer la : ls.getLayers().subList(0, ls.indexOf(first_chunk.lastKey()))) {
                                // exclusive last
                                la.apply(Patch.class, aff);
                            }
                        }
                    }
                    if (second_chunk.size() > 1) {
                        final AffineTransform aff = align(second_chunk, model);
                        if (propagate_to_last) {
                            for (final Layer la : ls.getLayers().subList(ls.indexOf(second_chunk.lastKey()) + 1, ls.size())) {
                                // exclusive last
                                la.apply(Patch.class, aff);
                            }
                        }
                    }
                    Display.repaint();
                    // Store current state
                    if (ds.size() > 0) {
                        final Displayable.DoEdits step2 = ls.addTransformStepWithData(ds);
                        if (patches.size() > 0) {
                            final ArrayList<DoStep> a2 = new ArrayList<DoStep>();
                            a2.add(new Displayable.DoTransforms().addAll(patches));
                            step2.addDependents(a2);
                        }
                    }
                }
            });
        }
    }, display.getProject());
    return true;
}
Also used : ArrayList(java.util.ArrayList) Comparator(java.util.Comparator) RigidModel2D(mpicbg.models.RigidModel2D) GenericDialog(ij.gui.GenericDialog) AbstractAffineModel2D(mpicbg.models.AbstractAffineModel2D) AffineModel2D(mpicbg.models.AffineModel2D) Worker(ini.trakem2.utils.Worker) SimilarityModel2D(mpicbg.models.SimilarityModel2D) Component(java.awt.Component) HashSet(java.util.HashSet) TreeMap(java.util.TreeMap) Point(mpicbg.models.Point) SortedMap(java.util.SortedMap) Collection(java.util.Collection) AffineTransform(java.awt.geom.AffineTransform) TranslationModel2D(mpicbg.models.TranslationModel2D) HashMap(java.util.HashMap) Map(java.util.Map) TreeMap(java.util.TreeMap) SortedMap(java.util.SortedMap)

Example 7 with AbstractAffineModel2D

use of mpicbg.models.AbstractAffineModel2D in project TrakEM2 by trakem2.

the class NonLinearTransformMode method createCT.

private CoordinateTransform createCT() throws Exception {
    final Collection<PointMatch> pm = new ArrayList<PointMatch>();
    for (final Point p : points) {
        pm.add(new PointMatch(new Point(p.getL()), new Point(p.getW())));
    }
    /*
		 * TODO replace this with the desired parameters of the transformation
		 */
    final MovingLeastSquaresTransform2 mlst = new MovingLeastSquaresTransform2();
    mlst.setAlpha(1.0f);
    Class<? extends AbstractAffineModel2D<?>> c = AffineModel2D.class;
    switch(points.size()) {
        case 1:
            c = TranslationModel2D.class;
            break;
        case 2:
            c = SimilarityModel2D.class;
            break;
        default:
            break;
    }
    mlst.setModel(c);
    mlst.setMatches(pm);
    return mlst;
}
Also used : PointMatch(mpicbg.models.PointMatch) MovingLeastSquaresTransform2(mpicbg.trakem2.transform.MovingLeastSquaresTransform2) ArrayList(java.util.ArrayList) AbstractAffineModel2D(mpicbg.models.AbstractAffineModel2D) AffineModel2D(mpicbg.trakem2.transform.AffineModel2D) Point(mpicbg.models.Point)

Example 8 with AbstractAffineModel2D

use of mpicbg.models.AbstractAffineModel2D in project TrakEM2 by trakem2.

the class Distortion_Correction method extractSIFTPointsThreaded.

protected static void extractSIFTPointsThreaded(final int index, final List<Feature>[] siftFeatures, final List<PointMatch>[] inliers, final AbstractAffineModel2D<?>[] models) {
    // save all matching candidates
    final List<PointMatch>[] candidates = new List[siftFeatures.length - 1];
    final Thread[] threads = MultiThreading.newThreads();
    // start at second
    final AtomicInteger ai = new AtomicInteger(0);
    for (int ithread = 0; ithread < threads.length; ++ithread) {
        threads[ithread] = new Thread() {

            @Override
            public void run() {
                setPriority(Thread.NORM_PRIORITY);
                for (int j = ai.getAndIncrement(); j < candidates.length; j = ai.getAndIncrement()) {
                    final int i = (j < index ? j : j + 1);
                    candidates[j] = FloatArray2DSIFT.createMatches(siftFeatures[index], siftFeatures[i], 1.5f, null, Float.MAX_VALUE, 0.5f);
                }
            }
        };
    }
    MultiThreading.startAndJoin(threads);
    // get rid of the outliers and save the rigid transformations to match
    // the inliers
    final AtomicInteger ai2 = new AtomicInteger(0);
    for (int ithread = 0; ithread < threads.length; ++ithread) {
        threads[ithread] = new Thread() {

            @Override
            public void run() {
                setPriority(Thread.NORM_PRIORITY);
                for (int i = ai2.getAndIncrement(); i < candidates.length; i = ai2.getAndIncrement()) {
                    final List<PointMatch> tmpInliers = new ArrayList<PointMatch>();
                    // RigidModel2D m =
                    // RigidModel2D.estimateBestModel(candidates.get(i),
                    // tmpInliers, sp.min_epsilon, sp.max_epsilon,
                    // sp.min_inlier_ratio);
                    final AbstractAffineModel2D<?> m;
                    switch(sp.expectedModelIndex) {
                        case 0:
                            m = new TranslationModel2D();
                            break;
                        case 1:
                            m = new RigidModel2D();
                            break;
                        case 2:
                            m = new SimilarityModel2D();
                            break;
                        case 3:
                            m = new AffineModel2D();
                            break;
                        default:
                            return;
                    }
                    boolean modelFound = false;
                    try {
                        modelFound = m.filterRansac(candidates[i], tmpInliers, 1000, sp.maxEpsilon, sp.minInlierRatio, 10);
                    } catch (final NotEnoughDataPointsException e) {
                        modelFound = false;
                    }
                    if (modelFound)
                        IJ.log("Model found:\n  " + candidates[i].size() + " candidates\n  " + tmpInliers.size() + " inliers\n  " + String.format("%.2f", m.getCost()) + "px average displacement");
                    else
                        IJ.log("No Model found.");
                    inliers[index * (sp.numberOfImages - 1) + i] = tmpInliers;
                    models[index * (sp.numberOfImages - 1) + i] = m;
                // System.out.println("**** MODEL ADDED: " +
                // (index*(sp.numberOfImages-1)+i));
                }
            }
        };
    }
    MultiThreading.startAndJoin(threads);
}
Also used : NotEnoughDataPointsException(mpicbg.models.NotEnoughDataPointsException) AbstractAffineModel2D(mpicbg.models.AbstractAffineModel2D) PointMatch(mpicbg.models.PointMatch) RigidModel2D(mpicbg.models.RigidModel2D) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AbstractAffineModel2D(mpicbg.models.AbstractAffineModel2D) AffineModel2D(mpicbg.models.AffineModel2D) ArrayList(java.util.ArrayList) List(java.util.List) TranslationModel2D(mpicbg.models.TranslationModel2D) SimilarityModel2D(mpicbg.models.SimilarityModel2D)

Example 9 with AbstractAffineModel2D

use of mpicbg.models.AbstractAffineModel2D in project TrakEM2 by trakem2.

the class Distortion_Correction method extractSIFTPoints.

protected void extractSIFTPoints(final int index, final List<Feature>[] siftFeatures, final List<List<PointMatch>> inliers, final List<AbstractAffineModel2D<?>> models) {
    // save all matching candidates
    final List<List<PointMatch>> candidates = new ArrayList<List<PointMatch>>();
    for (int j = 0; j < siftFeatures.length; j++) {
        if (index == j)
            continue;
        candidates.add(FloatArray2DSIFT.createMatches(siftFeatures[index], siftFeatures[j], 1.5f, null, Float.MAX_VALUE, 0.5f));
    }
    // get rid of the outliers and save the transformations to match the inliers
    for (int i = 0; i < candidates.size(); ++i) {
        final List<PointMatch> tmpInliers = new ArrayList<PointMatch>();
        final AbstractAffineModel2D<?> m;
        switch(sp.expectedModelIndex) {
            case 0:
                m = new TranslationModel2D();
                break;
            case 1:
                m = new RigidModel2D();
                break;
            case 2:
                m = new SimilarityModel2D();
                break;
            case 3:
                m = new AffineModel2D();
                break;
            default:
                return;
        }
        try {
            m.filterRansac(candidates.get(i), tmpInliers, 1000, sp.maxEpsilon, sp.minInlierRatio, 10);
        } catch (final NotEnoughDataPointsException e) {
            e.printStackTrace();
        }
        inliers.add(tmpInliers);
        models.add(m);
    }
}
Also used : PointMatch(mpicbg.models.PointMatch) NotEnoughDataPointsException(mpicbg.models.NotEnoughDataPointsException) RigidModel2D(mpicbg.models.RigidModel2D) ArrayList(java.util.ArrayList) AbstractAffineModel2D(mpicbg.models.AbstractAffineModel2D) AffineModel2D(mpicbg.models.AffineModel2D) ArrayList(java.util.ArrayList) List(java.util.List) TranslationModel2D(mpicbg.models.TranslationModel2D) SimilarityModel2D(mpicbg.models.SimilarityModel2D)

Example 10 with AbstractAffineModel2D

use of mpicbg.models.AbstractAffineModel2D in project TrakEM2 by trakem2.

the class Align method alignLayersLinearly.

/**
 * Align a range of layers by accumulating pairwise alignments of contiguous layers.
 *
 * @param layers The range of layers to align pairwise.
 * @param numThreads The number of threads to use.
 * @param filter The {@link Filter} to decide which {@link Patch} instances to use in each {@link Layer}. Can be null.
 */
public static final void alignLayersLinearly(final List<Layer> layers, final int numThreads, final Filter<Patch> filter) {
    param.sift.maxOctaveSize = 1600;
    if (!param.setup("Align layers linearly"))
        return;
    final Rectangle box = layers.get(0).getParent().getMinimalBoundingBox(Patch.class);
    final double scale = Math.min(1.0, Math.min((double) param.sift.maxOctaveSize / box.width, (double) param.sift.maxOctaveSize / box.height));
    final Param p = param.clone();
    p.maxEpsilon *= scale;
    final FloatArray2DSIFT sift = new FloatArray2DSIFT(p.sift);
    final SIFT ijSIFT = new SIFT(sift);
    Rectangle box1 = null;
    Rectangle box2 = null;
    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 i = 0;
    for (final Layer l : layers) {
        long s = System.currentTimeMillis();
        features1.clear();
        features1.addAll(features2);
        features2.clear();
        final Rectangle box3 = l.getMinimalBoundingBox(Patch.class);
        if (box3 == null)
            continue;
        box1 = box2;
        box2 = box3;
        final List<Patch> patches = l.getAll(Patch.class);
        if (null != filter) {
            for (final Iterator<Patch> it = patches.iterator(); it.hasNext(); ) {
                if (!filter.accept(it.next()))
                    it.remove();
            }
        }
        ijSIFT.extractFeatures(l.getProject().getLoader().getFlatImage(l, box2, scale, 0xffffffff, ImagePlus.GRAY8, Patch.class, patches, true).getProcessor(), features2);
        Utils.log(features2.size() + " features extracted in layer \"" + l.getTitle() + "\" (took " + (System.currentTimeMillis() - s) + " ms).");
        if (features1.size() > 0) {
            s = 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;
            }
            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)) {
                            Utils.log("Identity transform for " + inliers.size() + " matches rejected.");
                            candidates.removeAll(inliers);
                            inliers.clear();
                            again = true;
                        }
                    }
                } while (again);
            } catch (final NotEnoughDataPointsException e) {
                modelFound = false;
            }
            if (modelFound) {
                Utils.log("Model found for layer \"" + l.getTitle() + "\" and its predecessor:\n  correspondences  " + inliers.size() + " of " + candidates.size() + "\n  average residual error  " + (model.getCost() / scale) + " px\n  took " + (System.currentTimeMillis() - s) + " ms");
                final AffineTransform b = new AffineTransform();
                b.translate(box1.x, box1.y);
                b.scale(1.0f / scale, 1.0f / scale);
                b.concatenate(model.createAffine());
                b.scale(scale, scale);
                b.translate(-box2.x, -box2.y);
                a.concatenate(b);
                l.apply(Displayable.class, a);
                Display.repaint(l);
            } else {
                Utils.log("No model found for layer \"" + l.getTitle() + "\" and its predecessor:\n  correspondence candidates  " + candidates.size() + "\n  took " + (System.currentTimeMillis() - s) + " ms");
                a.setToIdentity();
            }
        }
        IJ.showProgress(++i, layers.size());
    }
}
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) RigidModel2D(mpicbg.trakem2.transform.RigidModel2D) AbstractAffineModel2D(mpicbg.models.AbstractAffineModel2D) AffineModel2D(mpicbg.models.AffineModel2D) InterpolatedAffineModel2D(mpicbg.models.InterpolatedAffineModel2D) SimilarityModel2D(mpicbg.models.SimilarityModel2D) 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)

Aggregations

AbstractAffineModel2D (mpicbg.models.AbstractAffineModel2D)14 ArrayList (java.util.ArrayList)12 AffineModel2D (mpicbg.models.AffineModel2D)11 PointMatch (mpicbg.models.PointMatch)11 SimilarityModel2D (mpicbg.models.SimilarityModel2D)10 NotEnoughDataPointsException (mpicbg.models.NotEnoughDataPointsException)9 Point (mpicbg.models.Point)9 Patch (ini.trakem2.display.Patch)7 AffineTransform (java.awt.geom.AffineTransform)7 Rectangle (java.awt.Rectangle)6 InterpolatedAffineModel2D (mpicbg.models.InterpolatedAffineModel2D)6 RigidModel2D (mpicbg.trakem2.transform.RigidModel2D)6 TranslationModel2D (mpicbg.trakem2.transform.TranslationModel2D)6 Layer (ini.trakem2.display.Layer)5 SIFT (mpicbg.ij.SIFT)5 Feature (mpicbg.imagefeatures.Feature)5 FloatArray2DSIFT (mpicbg.imagefeatures.FloatArray2DSIFT)5 RigidModel2D (mpicbg.models.RigidModel2D)4 TranslationModel2D (mpicbg.models.TranslationModel2D)4 Collection (java.util.Collection)3