Search in sources :

Example 6 with AbstractAffineTile2D

use of mpicbg.trakem2.align.AbstractAffineTile2D in project TrakEM2 by trakem2.

the class DistortionCorrectionTask method run.

public static final void run(final CorrectDistortionFromSelectionParam p, final List<Patch> patches, final Displayable active, final Layer layer, final Worker worker) {
    /* no multiple inheritance, so p cannot be an Align.ParamOptimize, working around legacy by copying data into one ... */
    final Align.ParamOptimize ap = new Align.ParamOptimize();
    ap.sift.set(p.sift);
    ap.desiredModelIndex = p.desiredModelIndex;
    ap.expectedModelIndex = p.expectedModelIndex;
    ap.maxEpsilon = p.maxEpsilon;
    ap.minInlierRatio = p.minInlierRatio;
    ap.rod = p.rod;
    ap.identityTolerance = p.identityTolerance;
    ap.lambda = p.lambdaRegularize;
    ap.maxIterations = p.maxIterationsOptimize;
    ap.maxPlateauwidth = p.maxPlateauwidthOptimize;
    ap.minNumInliers = p.minNumInliers;
    ap.regularize = p.regularize;
    ap.regularizerModelIndex = p.regularizerIndex;
    ap.rejectIdentity = p.rejectIdentity;
    /**
     * Get all patches that will be affected.
     */
    final List<Patch> allPatches = new ArrayList<Patch>();
    for (final Layer l : layer.getParent().getLayers().subList(p.firstLayerIndex, p.lastLayerIndex + 1)) for (final Displayable d : l.getDisplayables(Patch.class)) allPatches.add((Patch) d);
    /**
     * Unset the coordinate transforms of all patches if desired.
     */
    if (p.clearTransform) {
        if (worker != null)
            worker.setTaskName("Clearing present transforms");
        setCoordinateTransform(allPatches, null, Runtime.getRuntime().availableProcessors());
        Display.repaint();
    }
    if (worker != null)
        worker.setTaskName("Establishing SIFT correspondences");
    final List<AbstractAffineTile2D<?>> tiles = new ArrayList<AbstractAffineTile2D<?>>();
    final List<AbstractAffineTile2D<?>> fixedTiles = new ArrayList<AbstractAffineTile2D<?>>();
    final List<Patch> fixedPatches = new ArrayList<Patch>();
    if (active != null && active instanceof Patch)
        fixedPatches.add((Patch) active);
    Align.tilesFromPatches(ap, patches, fixedPatches, tiles, fixedTiles);
    final List<AbstractAffineTile2D<?>[]> tilePairs = new ArrayList<AbstractAffineTile2D<?>[]>();
    if (p.tilesAreInPlace)
        AbstractAffineTile2D.pairOverlappingTiles(tiles, tilePairs);
    else
        AbstractAffineTile2D.pairTiles(tiles, tilePairs);
    AbstractAffineTile2D<?> fixedTile = null;
    if (fixedTiles.size() > 0)
        fixedTile = fixedTiles.get(0);
    else
        fixedTile = tiles.get(0);
    Align.connectTilePairs(ap, tiles, tilePairs, p.maxNumThreadsSift, p.multipleHypotheses);
    /**
     * Shift all local coordinates into the original image frame
     */
    for (final AbstractAffineTile2D<?> tile : tiles) {
        final Rectangle box = tile.getPatch().getCoordinateTransformBoundingBox();
        for (final PointMatch m : tile.getMatches()) {
            final double[] l = m.getP1().getL();
            final double[] w = m.getP1().getW();
            l[0] += box.x;
            l[1] += box.y;
            w[0] = l[0];
            w[1] = l[1];
        }
    }
    if (Thread.currentThread().isInterrupted())
        return;
    final List<Set<Tile<?>>> graphs = AbstractAffineTile2D.identifyConnectedGraphs(tiles);
    if (graphs.size() > 1)
        Utils.log("Could not interconnect all images with correspondences.  ");
    final List<AbstractAffineTile2D<?>> interestingTiles;
    /**
     * Find largest graph.
     */
    Set<Tile<?>> largestGraph = null;
    for (final Set<Tile<?>> graph : graphs) if (largestGraph == null || largestGraph.size() < graph.size())
        largestGraph = graph;
    interestingTiles = new ArrayList<AbstractAffineTile2D<?>>();
    for (final Tile<?> t : largestGraph) interestingTiles.add((AbstractAffineTile2D<?>) t);
    if (Thread.currentThread().isInterrupted())
        return;
    Utils.log("Estimating lens model:");
    /* initialize with pure affine */
    Align.optimizeTileConfiguration(ap, interestingTiles, fixedTiles);
    /* measure the current error */
    double e = 0;
    int n = 0;
    for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) {
        e += pm.getDistance();
        ++n;
    }
    e /= n;
    double dEpsilon_i = 0;
    double epsilon_i = e;
    double dEpsilon_0 = 0;
    NonLinearTransform lensModel = null;
    Utils.log("0: epsilon = " + e);
    /* Store original point locations */
    final HashMap<Point, Point> originalPoints = new HashMap<Point, Point>();
    for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) originalPoints.put(pm.getP1(), pm.getP1().clone());
    /* ad hoc conditions to terminate iteration:
		 * small improvement ( 1/1000) relative to first iteration
		 * less than 20 iterations
		 * at least 2 iterations */
    for (int i = 1; i < 20 && (i < 2 || dEpsilon_i <= dEpsilon_0 / 1000); ++i) {
        if (Thread.currentThread().isInterrupted())
            return;
        /* Some data shuffling for the lens correction interface */
        final List<PointMatchCollectionAndAffine> matches = new ArrayList<PointMatchCollectionAndAffine>();
        for (final AbstractAffineTile2D<?>[] tilePair : tilePairs) {
            final AffineTransform a = tilePair[0].createAffine();
            a.preConcatenate(tilePair[1].getModel().createInverseAffine());
            final Collection<PointMatch> commonMatches = new ArrayList<PointMatch>();
            tilePair[0].commonPointMatches(tilePair[1], commonMatches);
            final Collection<PointMatch> originalCommonMatches = new ArrayList<PointMatch>();
            for (final PointMatch pm : commonMatches) originalCommonMatches.add(new PointMatch(originalPoints.get(pm.getP1()), originalPoints.get(pm.getP2())));
            matches.add(new PointMatchCollectionAndAffine(a, originalCommonMatches));
        }
        if (worker != null)
            worker.setTaskName("Estimating lens distortion correction");
        lensModel = Distortion_Correction.createInverseDistortionModel(matches, p.dimension, p.lambda, (int) fixedTile.getWidth(), (int) fixedTile.getHeight());
        /* update local points */
        for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) {
            final Point currentPoint = pm.getP1();
            final Point originalPoint = originalPoints.get(currentPoint);
            final double[] l = currentPoint.getL();
            final double[] lo = originalPoint.getL();
            l[0] = lo[0];
            l[1] = lo[1];
            lensModel.applyInPlace(l);
        }
        /* re-optimize */
        Align.optimizeTileConfiguration(ap, interestingTiles, fixedTiles);
        /* measure the current error */
        e = 0;
        n = 0;
        for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) {
            e += pm.getDistance();
            ++n;
        }
        e /= n;
        dEpsilon_i = e - epsilon_i;
        epsilon_i = e;
        if (i == 1)
            dEpsilon_0 = dEpsilon_i;
        Utils.log(i + ": epsilon = " + e);
        Utils.log(i + ": delta epsilon = " + dEpsilon_i);
    }
    if (lensModel != null) {
        if (p.visualize) {
            if (Thread.currentThread().isInterrupted())
                return;
            if (worker != null)
                worker.setTaskName("Visualizing lens distortion correction");
            lensModel.visualizeSmall(p.lambda);
        }
        if (worker != null)
            worker.setTaskName("Applying lens distortion correction");
        appendCoordinateTransform(allPatches, lensModel, Runtime.getRuntime().availableProcessors());
        Utils.log("Done.");
    } else
        Utils.log("No lens model found.");
}
Also used : Set(java.util.Set) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) PointMatchCollectionAndAffine(lenscorrection.Distortion_Correction.PointMatchCollectionAndAffine) Displayable(ini.trakem2.display.Displayable) Align(mpicbg.trakem2.align.Align) AbstractAffineTile2D(mpicbg.trakem2.align.AbstractAffineTile2D) Tile(mpicbg.models.Tile) Point(mpicbg.models.Point) Layer(ini.trakem2.display.Layer) Point(mpicbg.models.Point) PointMatch(mpicbg.models.PointMatch) AffineTransform(java.awt.geom.AffineTransform) Patch(ini.trakem2.display.Patch)

Example 7 with AbstractAffineTile2D

use of mpicbg.trakem2.align.AbstractAffineTile2D in project TrakEM2 by trakem2.

the class StitchingTEM method montageWithPhaseCorrelation.

/**
 * Perform montage based on phase correlation
 * @param col collection of patches
 * @param param phase correlation parameters
 */
public static void montageWithPhaseCorrelation(final Collection<Patch> col, final PhaseCorrelationParam param) {
    if (null == col || col.size() < 1)
        return;
    final ArrayList<Patch> al = new ArrayList<Patch>(col);
    final ArrayList<AbstractAffineTile2D<?>> tiles = new ArrayList<AbstractAffineTile2D<?>>();
    final ArrayList<AbstractAffineTile2D<?>> fixed_tiles = new ArrayList<AbstractAffineTile2D<?>>();
    for (final Patch p : al) {
        // Pre-check: just a warning
        final int aff_type = p.getAffineTransform().getType();
        switch(p.getAffineTransform().getType()) {
            case AffineTransform.TYPE_IDENTITY:
            case AffineTransform.TYPE_TRANSLATION:
                // ok
                break;
            default:
                Utils.log2("WARNING: patch with a non-translation transform: " + p);
                break;
        }
        // create tiles
        final TranslationTile2D tile = new TranslationTile2D(new TranslationModel2D(), p);
        tiles.add(tile);
        if (p.isLocked2()) {
            Utils.log("Added fixed (locked) tile " + p);
            fixed_tiles.add(tile);
        }
    }
    // Get acceptable values
    double cc_scale = param.cc_scale;
    if (cc_scale < 0 || cc_scale > 1) {
        Utils.log("Unacceptable cc_scale of " + param.cc_scale + ". Using 1 instead.");
        cc_scale = 1;
    }
    float overlap = param.overlap;
    if (overlap < 0 || overlap > 1) {
        Utils.log("Unacceptable overlap of " + param.overlap + ". Using 1 instead.");
        overlap = 1;
    }
    for (int i = 0; i < al.size(); i++) {
        final Patch p1 = al.get(i);
        final Rectangle r1 = p1.getBoundingBox();
        // find overlapping, add as connections
        for (int j = i + 1; j < al.size(); j++) {
            if (Thread.currentThread().isInterrupted())
                return;
            final Patch p2 = al.get(j);
            final Rectangle r2 = p2.getBoundingBox();
            if (r1.intersects(r2)) {
                // Skip if it's a diagonal overlap
                final int dx = Math.abs(r1.x - r2.x);
                final int dy = Math.abs(r1.y - r2.y);
                if (dx > r1.width / 2 && dy > r1.height / 2) {
                    // skip diagonal match
                    Utils.log2("Skipping diagonal overlap between " + p1 + " and " + p2);
                    continue;
                }
                p1.getProject().getLoader().releaseToFit((long) (p1.getWidth() * p1.getHeight() * 25));
                final double[] R;
                if (1 == overlap) {
                    R = correlate(p1, p2, overlap, cc_scale, TOP_BOTTOM, 0, 0, param.min_R);
                    if (SUCCESS == R[2]) {
                        addMatches(tiles.get(i), tiles.get(j), R[0], R[1]);
                    }
                } else {
                    switch(getClosestOverlapLocation(p1, p2)) {
                        case // p1 overlaps p2 from the left
                        0:
                            R = correlate(p1, p2, overlap, cc_scale, LEFT_RIGHT, 0, 0, param.min_R);
                            if (SUCCESS == R[2]) {
                                addMatches(tiles.get(i), tiles.get(j), R[0], R[1]);
                            }
                            break;
                        case // p1 overlaps p2 from the top
                        1:
                            R = correlate(p1, p2, overlap, cc_scale, TOP_BOTTOM, 0, 0, param.min_R);
                            if (SUCCESS == R[2]) {
                                addMatches(tiles.get(i), tiles.get(j), R[0], R[1]);
                            }
                            break;
                        case // p1 overlaps p2 from the right
                        2:
                            R = correlate(p2, p1, overlap, cc_scale, LEFT_RIGHT, 0, 0, param.min_R);
                            if (SUCCESS == R[2]) {
                                addMatches(tiles.get(j), tiles.get(i), R[0], R[1]);
                            }
                            break;
                        case // p1 overlaps p2 from the bottom
                        3:
                            R = correlate(p2, p1, overlap, cc_scale, TOP_BOTTOM, 0, 0, param.min_R);
                            if (SUCCESS == R[2]) {
                                addMatches(tiles.get(j), tiles.get(i), R[0], R[1]);
                            }
                            break;
                        default:
                            Utils.log("Unknown overlap direction!");
                            continue;
                    }
                }
            }
        }
    }
    if (param.remove_disconnected || param.hide_disconnected) {
        for (final Iterator<AbstractAffineTile2D<?>> it = tiles.iterator(); it.hasNext(); ) {
            final AbstractAffineTile2D<?> t = it.next();
            if (null != t.getMatches() && t.getMatches().isEmpty()) {
                if (param.hide_disconnected)
                    t.getPatch().setVisible(false);
                else if (param.remove_disconnected)
                    t.getPatch().remove(false);
                it.remove();
            }
        }
    }
    // Optimize tile configuration by removing bad matches
    optimizeTileConfiguration(tiles, fixed_tiles, param);
    for (final AbstractAffineTile2D<?> t : tiles) t.getPatch().setAffineTransform(t.getModel().createAffine());
    try {
        Display.repaint(al.get(0).getLayer());
    } catch (final Exception e) {
    }
}
Also used : TranslationTile2D(mpicbg.trakem2.align.TranslationTile2D) AbstractAffineTile2D(mpicbg.trakem2.align.AbstractAffineTile2D) ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) Point(mpicbg.models.Point) TranslationModel2D(mpicbg.models.TranslationModel2D) Patch(ini.trakem2.display.Patch)

Example 8 with AbstractAffineTile2D

use of mpicbg.trakem2.align.AbstractAffineTile2D in project TrakEM2 by trakem2.

the class AlignTask method alignMultiLayerMosaicTask.

@SuppressWarnings({ "unchecked", "rawtypes" })
public static final void alignMultiLayerMosaicTask(final List<Layer> layerRange, final Patch nail, final Align.Param cp, final Align.ParamOptimize p, final Align.ParamOptimize pcp, final boolean tilesAreInPlaceIn, final boolean largestGraphOnlyIn, final boolean hideDisconnectedTilesIn, final boolean deleteDisconnectedTilesIn, final boolean deformIn) {
    /* register */
    final List<AbstractAffineTile2D<?>> allTiles = new ArrayList<AbstractAffineTile2D<?>>();
    final List<AbstractAffineTile2D<?>> allFixedTiles = new ArrayList<AbstractAffineTile2D<?>>();
    final List<AbstractAffineTile2D<?>> previousLayerTiles = new ArrayList<AbstractAffineTile2D<?>>();
    final HashMap<Patch, PointMatch> tileCenterPoints = new HashMap<Patch, PointMatch>();
    final Collection<Patch> fixedPatches = new HashSet<Patch>();
    if (null != nail)
        fixedPatches.add(nail);
    Layer previousLayer = null;
    for (final Layer layer : layerRange) {
        /* align all tiles in the layer */
        final List<Patch> patches = new ArrayList<Patch>();
        for (// ignore hidden tiles
        final Displayable a : // ignore hidden tiles
        layer.getDisplayables(Patch.class, true)) if (a instanceof Patch)
            patches.add((Patch) a);
        final List<AbstractAffineTile2D<?>> currentLayerTiles = new ArrayList<AbstractAffineTile2D<?>>();
        final List<AbstractAffineTile2D<?>> fixedTiles = new ArrayList<AbstractAffineTile2D<?>>();
        Align.tilesFromPatches(p, patches, fixedPatches, currentLayerTiles, fixedTiles);
        // Will consider graphs and hide/delete tiles when all cross-layer graphs are found.
        alignTiles(p, currentLayerTiles, fixedTiles, tilesAreInPlaceIn, false, false, false);
        if (Thread.currentThread().isInterrupted())
            return;
        /* connect to the previous layer */
        /* generate tiles with the cross-section model from the current layer tiles */
        /* ------------------------------------------------------------------------ */
        /* TODO step back and make tiles bare containers for a patch and a model such that by changing the model the tile can be reused */
        final HashMap<Patch, AbstractAffineTile2D<?>> currentLayerPatchTiles = new HashMap<Patch, AbstractAffineTile2D<?>>();
        for (final AbstractAffineTile2D<?> t : currentLayerTiles) currentLayerPatchTiles.put(t.getPatch(), t);
        final List<AbstractAffineTile2D<?>> csCurrentLayerTiles = new ArrayList<AbstractAffineTile2D<?>>();
        final Set<AbstractAffineTile2D<?>> csFixedTiles = new HashSet<AbstractAffineTile2D<?>>();
        Align.tilesFromPatches(cp, patches, fixedPatches, csCurrentLayerTiles, csFixedTiles);
        final HashMap<Tile<?>, AbstractAffineTile2D<?>> tileTiles = new HashMap<Tile<?>, AbstractAffineTile2D<?>>();
        for (final AbstractAffineTile2D<?> t : csCurrentLayerTiles) tileTiles.put(currentLayerPatchTiles.get(t.getPatch()), t);
        for (final AbstractAffineTile2D<?> t : currentLayerTiles) {
            final AbstractAffineTile2D<?> csLayerTile = tileTiles.get(t);
            csLayerTile.addMatches(t.getMatches());
            for (final Tile<?> ct : t.getConnectedTiles()) csLayerTile.addConnectedTile(tileTiles.get(ct));
        }
        /* add a fixed tile only if there was a Patch selected */
        allFixedTiles.addAll(csFixedTiles);
        /* first, align connected graphs to each other */
        /* graphs in the current layer */
        final List<Set<Tile<?>>> currentLayerGraphs = AbstractAffineTile2D.identifyConnectedGraphs(csCurrentLayerTiles);
        if (Thread.currentThread().isInterrupted())
            return;
        // /* TODO just for visualization */
        // for ( final Set< Tile< ? > > graph : currentLayerGraphs )
        // {
        // Display.getFront().getSelection().clear();
        // Display.getFront().setLayer( ( ( AbstractAffineTile2D< ? > )graph.iterator().next() ).getPatch().getLayer() );
        // 
        // for ( final Tile< ? > tile : graph )
        // {
        // Display.getFront().getSelection().add( ( ( AbstractAffineTile2D< ? > )tile ).getPatch() );
        // Display.repaint();
        // }
        // Utils.showMessage( "OK" );
        // }
        /* graphs from the whole system that are present in the previous layer */
        final List<Set<Tile<?>>> graphs = AbstractAffineTile2D.identifyConnectedGraphs(allTiles);
        final HashMap<Set<Tile<?>>, Set<Tile<?>>> graphGraphs = new HashMap<Set<Tile<?>>, Set<Tile<?>>>();
        for (final Set<Tile<?>> graph : graphs) {
            if (Thread.currentThread().isInterrupted())
                return;
            final Set<Tile<?>> previousLayerGraph = new HashSet<Tile<?>>();
            for (final Tile<?> tile : previousLayerTiles) {
                if (graph.contains(tile)) {
                    graphGraphs.put(graph, previousLayerGraph);
                    previousLayerGraph.add(tile);
                }
            }
        }
        final Collection<Set<Tile<?>>> previousLayerGraphs = graphGraphs.values();
        // /* TODO just for visualization */
        // for ( final Set< Tile< ? > > graph : previousLayerGraphs )
        // {
        // Display.getFront().getSelection().clear();
        // Display.getFront().setLayer( ( ( AbstractAffineTile2D< ? > )graph.iterator().next() ).getPatch().getLayer() );
        // 
        // for ( final Tile< ? > tile : graph )
        // {
        // Display.getFront().getSelection().add( ( ( AbstractAffineTile2D< ? > )tile ).getPatch() );
        // Display.repaint();
        // }
        // Utils.showMessage( "OK" );
        // }
        /* generate snapshots of the graphs and preregister them using the parameters defined in cp */
        final List<AbstractAffineTile2D<?>[]> crossLayerTilePairs = new ArrayList<AbstractAffineTile2D<?>[]>();
        for (final Set<Tile<?>> currentLayerGraph : currentLayerGraphs) {
            for (final Set<Tile<?>> previousLayerGraph : previousLayerGraphs) {
                if (Thread.currentThread().isInterrupted())
                    return;
                alignGraphs(cp, layer, previousLayer, currentLayerGraph, previousLayerGraph);
                /* TODO this is pointless data shuffling just for type incompatibility---fix this at the root */
                final ArrayList<AbstractAffineTile2D<?>> previousLayerGraphTiles = new ArrayList<AbstractAffineTile2D<?>>();
                previousLayerGraphTiles.addAll((Set) previousLayerGraph);
                final ArrayList<AbstractAffineTile2D<?>> currentLayerGraphTiles = new ArrayList<AbstractAffineTile2D<?>>();
                currentLayerGraphTiles.addAll((Set) currentLayerGraph);
                AbstractAffineTile2D.pairOverlappingTiles(previousLayerGraphTiles, currentLayerGraphTiles, crossLayerTilePairs);
            }
        }
        /* ------------------------------------------------------------------------ */
        /* this is without the affine/rigid approximation per graph */
        // AbstractAffineTile2D.pairTiles( previousLayerTiles, csCurrentLayerTiles, crossLayerTilePairs );
        Align.connectTilePairs(cp, csCurrentLayerTiles, crossLayerTilePairs, Runtime.getRuntime().availableProcessors());
        if (Thread.currentThread().isInterrupted())
            return;
        // for ( final AbstractAffineTile2D< ? >[] tilePair : crossLayerTilePairs )
        // {
        // Display.getFront().setLayer( tilePair[ 0 ].getPatch().getLayer() );
        // Display.getFront().getSelection().clear();
        // Display.getFront().getSelection().add( tilePair[ 0 ].getPatch() );
        // Display.getFront().getSelection().add( tilePair[ 1 ].getPatch() );
        // 
        // Utils.showMessage( "1: OK?" );
        // 
        // Display.getFront().setLayer( tilePair[ 1 ].getPatch().getLayer() );
        // Display.getFront().getSelection().clear();
        // Display.getFront().getSelection().add( tilePair[ 0 ].getPatch() );
        // Display.getFront().getSelection().add( tilePair[ 1 ].getPatch() );
        // 
        // Utils.showMessage( "2: OK?" );
        // }
        /* prepare the next loop */
        allTiles.addAll(csCurrentLayerTiles);
        previousLayerTiles.clear();
        previousLayerTiles.addAll(csCurrentLayerTiles);
        /* optimize */
        Align.optimizeTileConfiguration(pcp, allTiles, allFixedTiles);
        if (Thread.currentThread().isInterrupted())
            return;
        for (final AbstractAffineTile2D<?> t : allTiles) t.getPatch().setAffineTransform(t.getModel().createAffine());
        previousLayer = layer;
    }
    final List<Set<Tile<?>>> graphs = AbstractAffineTile2D.identifyConnectedGraphs(allTiles);
    final List<AbstractAffineTile2D<?>> interestingTiles = new ArrayList<AbstractAffineTile2D<?>>();
    if (largestGraphOnlyIn && (hideDisconnectedTilesIn || deleteDisconnectedTilesIn)) {
        if (Thread.currentThread().isInterrupted())
            return;
        /* find largest graph. */
        Set<Tile<?>> largestGraph = null;
        for (final Set<Tile<?>> graph : graphs) if (largestGraph == null || largestGraph.size() < graph.size())
            largestGraph = graph;
        final Set<AbstractAffineTile2D<?>> tiles_to_keep = new HashSet<AbstractAffineTile2D<?>>();
        for (final Tile<?> t : largestGraph) tiles_to_keep.add((AbstractAffineTile2D<?>) t);
        if (hideDisconnectedTilesIn)
            for (final AbstractAffineTile2D<?> t : allTiles) if (!tiles_to_keep.contains(t))
                t.getPatch().setVisible(false);
        if (deleteDisconnectedTilesIn)
            for (final AbstractAffineTile2D<?> t : allTiles) if (!tiles_to_keep.contains(t))
                t.getPatch().remove(false);
        interestingTiles.addAll(tiles_to_keep);
    } else
        interestingTiles.addAll(allTiles);
    if (deformIn) {
        /* ############################################ */
        /* experimental: use the center points of all tiles to define a MLS deformation from the pure intra-layer registration to the globally optimal */
        Utils.log("deforming...");
        /* store the center location of each single tile for later deformation */
        for (final AbstractAffineTile2D<?> t : interestingTiles) {
            final double[] c = new double[] { t.getWidth() / 2.0, t.getHeight() / 2.0 };
            t.getModel().applyInPlace(c);
            final Point q = new Point(c);
            tileCenterPoints.put(t.getPatch(), new PointMatch(q.clone(), q));
        }
        for (final Layer layer : layerRange) {
            Utils.log("layer" + layer);
            if (Thread.currentThread().isInterrupted())
                return;
            /* again, align all tiles in the layer */
            final List<Patch> patches = new ArrayList<Patch>();
            for (final Displayable a : layer.getDisplayables(Patch.class)) if (a instanceof Patch)
                patches.add((Patch) a);
            final List<AbstractAffineTile2D<?>> currentLayerTiles = new ArrayList<AbstractAffineTile2D<?>>();
            final List<AbstractAffineTile2D<?>> fixedTiles = new ArrayList<AbstractAffineTile2D<?>>();
            Align.tilesFromPatches(p, patches, fixedPatches, currentLayerTiles, fixedTiles);
            /* add a fixed tile only if there was a Patch selected */
            allFixedTiles.addAll(fixedTiles);
            // will consider graphs and hide/delete tiles when all cross-layer graphs are found
            alignTiles(p, currentLayerTiles, fixedTiles, true, false, false, false);
            /* for each independent graph do an independent transform */
            final List<Set<Tile<?>>> currentLayerGraphs = AbstractAffineTile2D.identifyConnectedGraphs(currentLayerTiles);
            for (final Set<Tile<?>> graph : currentLayerGraphs) {
                /* update the tile-center pointmatches */
                final Collection<PointMatch> matches = new ArrayList<PointMatch>();
                final Collection<AbstractAffineTile2D<?>> toBeDeformedTiles = new ArrayList<AbstractAffineTile2D<?>>();
                for (final AbstractAffineTile2D<?> t : (Collection<AbstractAffineTile2D<?>>) (Collection) graph) {
                    final PointMatch pm = tileCenterPoints.get(t.getPatch());
                    if (pm == null)
                        continue;
                    final double[] pl = pm.getP1().getL();
                    pl[0] = t.getWidth() / 2.0;
                    pl[1] = t.getHeight() / 2.0;
                    t.getModel().applyInPlace(pl);
                    matches.add(pm);
                    toBeDeformedTiles.add(t);
                }
                for (final AbstractAffineTile2D<?> t : toBeDeformedTiles) {
                    if (Thread.currentThread().isInterrupted())
                        return;
                    try {
                        final Patch patch = t.getPatch();
                        final Rectangle pbox = patch.getCoordinateTransformBoundingBox();
                        final AffineTransform pat = new AffineTransform();
                        pat.translate(-pbox.x, -pbox.y);
                        pat.preConcatenate(patch.getAffineTransform());
                        final mpicbg.trakem2.transform.AffineModel2D toWorld = new mpicbg.trakem2.transform.AffineModel2D();
                        toWorld.set(pat);
                        final MovingLeastSquaresTransform2 mlst = Align.createMLST(matches, 1.0f);
                        final CoordinateTransformList<CoordinateTransform> ctl = new CoordinateTransformList<CoordinateTransform>();
                        ctl.add(toWorld);
                        ctl.add(mlst);
                        ctl.add(toWorld.createInverse());
                        patch.appendCoordinateTransform(ctl);
                        patch.getProject().getLoader().regenerateMipMaps(patch);
                    } catch (final Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    layerRange.get(0).getParent().setMinimumDimensions();
    IJ.log("Done: register multi-layer mosaic.");
    return;
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) LayerSet(ini.trakem2.display.LayerSet) HashMap(java.util.HashMap) CoordinateTransformList(mpicbg.trakem2.transform.CoordinateTransformList) ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) AbstractAffineModel2D(mpicbg.models.AbstractAffineModel2D) AffineModel2D(mpicbg.models.AffineModel2D) HashSet(java.util.HashSet) Displayable(ini.trakem2.display.Displayable) Tile(mpicbg.models.Tile) Point(mpicbg.models.Point) Layer(ini.trakem2.display.Layer) NotEnoughDataPointsException(mpicbg.models.NotEnoughDataPointsException) NoninvertibleModelException(mpicbg.models.NoninvertibleModelException) NoninvertibleTransformException(java.awt.geom.NoninvertibleTransformException) PointMatch(mpicbg.models.PointMatch) MovingLeastSquaresTransform2(mpicbg.trakem2.transform.MovingLeastSquaresTransform2) Collection(java.util.Collection) AffineTransform(java.awt.geom.AffineTransform) Patch(ini.trakem2.display.Patch) CoordinateTransform(mpicbg.trakem2.transform.CoordinateTransform) InvertibleCoordinateTransform(mpicbg.trakem2.transform.InvertibleCoordinateTransform)

Example 9 with AbstractAffineTile2D

use of mpicbg.trakem2.align.AbstractAffineTile2D in project TrakEM2 by trakem2.

the class Align method alignTileCollections.

/**
 * Align two collections of tiles
 * @param p
 * @param a
 * @param b
 */
public static final void alignTileCollections(final Param p, final Collection<AbstractAffineTile2D<?>> a, final Collection<AbstractAffineTile2D<?>> b) {
    final ArrayList<Patch> pa = new ArrayList<Patch>();
    final ArrayList<Patch> pb = new ArrayList<Patch>();
    for (final AbstractAffineTile2D<?> t : a) pa.add(t.getPatch());
    for (final AbstractAffineTile2D<?> t : b) pb.add(t.getPatch());
    final Layer la = pa.iterator().next().getLayer();
    final Layer lb = pb.iterator().next().getLayer();
    final Rectangle boxA = Displayable.getBoundingBox(pa, null);
    final Rectangle boxB = Displayable.getBoundingBox(pb, null);
    final double scale = Math.min(1.0, Math.min(Math.min((double) p.sift.maxOctaveSize / boxA.width, (double) p.sift.maxOctaveSize / boxA.height), Math.min((double) p.sift.maxOctaveSize / boxB.width, (double) p.sift.maxOctaveSize / boxB.height)));
    final Param pp = p.clone();
    pp.maxEpsilon *= scale;
    final FloatArray2DSIFT sift = new FloatArray2DSIFT(pp.sift);
    final SIFT ijSIFT = new SIFT(sift);
    final Collection<Feature> featuresA = new ArrayList<Feature>();
    final Collection<Feature> featuresB = new ArrayList<Feature>();
    final List<PointMatch> candidates = new ArrayList<PointMatch>();
    final List<PointMatch> inliers = new ArrayList<PointMatch>();
    long s = System.currentTimeMillis();
    ijSIFT.extractFeatures(la.getProject().getLoader().getFlatImage(la, boxA, scale, 0xffffffff, ImagePlus.GRAY8, null, pa, true, Color.GRAY).getProcessor(), featuresA);
    Utils.log(featuresA.size() + " features extracted in graph A in layer \"" + la.getTitle() + "\" (took " + (System.currentTimeMillis() - s) + " ms).");
    s = System.currentTimeMillis();
    ijSIFT.extractFeatures(lb.getProject().getLoader().getFlatImage(lb, boxB, scale, 0xffffffff, ImagePlus.GRAY8, null, pb, true, Color.GRAY).getProcessor(), featuresB);
    Utils.log(featuresB.size() + " features extracted in graph B in layer \"" + lb.getTitle() + "\" (took " + (System.currentTimeMillis() - s) + " ms).");
    if (featuresA.size() > 0 && featuresB.size() > 0) {
        s = System.currentTimeMillis();
        FeatureTransform.matchFeatures(featuresA, featuresB, candidates, pp.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 graph A and B in layers \"" + la.getTitle() + "\" and \"" + lb.getTitle() + "\":\n  correspondences  " + inliers.size() + " of " + candidates.size() + "\n  average residual error  " + (model.getCost() / scale) + " px\n  took " + (System.currentTimeMillis() - s) + " ms");
            final AffineTransform at = new AffineTransform();
            at.translate(boxA.x, boxA.y);
            at.scale(1.0f / scale, 1.0f / scale);
            at.concatenate(model.createAffine());
            at.scale(scale, scale);
            at.translate(-boxB.x, -boxB.y);
            for (final Patch t : pa) t.preTransform(at, false);
            Display.repaint(la);
        } else
            Utils.log("No model found for graph A and B in layers \"" + la.getTitle() + "\" and \"" + lb.getTitle() + "\":\n  correspondence candidates  " + candidates.size() + "\n  took " + (System.currentTimeMillis() - s) + " ms");
    }
}
Also used : NotEnoughDataPointsException(mpicbg.models.NotEnoughDataPointsException) SIFT(mpicbg.ij.SIFT) FloatArray2DSIFT(mpicbg.imagefeatures.FloatArray2DSIFT) ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) 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) FloatArray2DSIFT(mpicbg.imagefeatures.FloatArray2DSIFT) PointMatch(mpicbg.models.PointMatch) AffineTransform(java.awt.geom.AffineTransform) TranslationModel2D(mpicbg.trakem2.transform.TranslationModel2D) Patch(ini.trakem2.display.Patch)

Aggregations

ArrayList (java.util.ArrayList)8 Rectangle (java.awt.Rectangle)7 Point (mpicbg.models.Point)7 PointMatch (mpicbg.models.PointMatch)7 Patch (ini.trakem2.display.Patch)6 AbstractAffineModel2D (mpicbg.models.AbstractAffineModel2D)5 AffineModel2D (mpicbg.models.AffineModel2D)5 AffineTransform (java.awt.geom.AffineTransform)4 NotEnoughDataPointsException (mpicbg.models.NotEnoughDataPointsException)4 SimilarityModel2D (mpicbg.models.SimilarityModel2D)4 Tile (mpicbg.models.Tile)4 AbstractAffineTile2D (mpicbg.trakem2.align.AbstractAffineTile2D)4 Displayable (ini.trakem2.display.Displayable)3 Layer (ini.trakem2.display.Layer)3 HashMap (java.util.HashMap)3 Set (java.util.Set)3 TranslationModel2D (mpicbg.models.TranslationModel2D)3 RigidModel2D (mpicbg.trakem2.transform.RigidModel2D)3 TranslationModel2D (mpicbg.trakem2.transform.TranslationModel2D)3 SIFT (mpicbg.ij.SIFT)2