Search in sources :

Example 1 with AbstractAffineTile2D

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

the class StitchingTEM method stitchTopLeft.

/**
 * Stitch array of patches with upper left rule
 *
 * @param patch
 * @param grid_width
 * @param default_bottom_top_overlap
 * @param default_left_right_overlap
 * @param optimize
 * @return
 */
private static Runnable stitchTopLeft(final Patch[] patch, final int grid_width, final double default_bottom_top_overlap, final double default_left_right_overlap, final boolean optimize, final PhaseCorrelationParam param) {
    return new Runnable() {

        @Override
        public void run() {
            try {
                final int LEFT = 0, TOP = 1;
                int prev_i = 0;
                int prev = LEFT;
                double[] R1 = null, R2 = null;
                // for minimization:
                final ArrayList<AbstractAffineTile2D<?>> al_tiles = new ArrayList<AbstractAffineTile2D<?>>();
                // first patch-tile:
                final TranslationModel2D first_tile_model = new TranslationModel2D();
                // first_tile_model.getAffine().setTransform( patch[ 0 ].getAffineTransform() );
                first_tile_model.set((float) patch[0].getAffineTransform().getTranslateX(), (float) patch[0].getAffineTransform().getTranslateY());
                al_tiles.add(new TranslationTile2D(first_tile_model, patch[0]));
                for (int i = 1; i < patch.length; i++) {
                    if (Thread.currentThread().isInterrupted()) {
                        return;
                    }
                    // boundary checks: don't allow displacements beyond these values
                    final double default_dx = default_left_right_overlap;
                    final double default_dy = default_bottom_top_overlap;
                    // for minimization:
                    AbstractAffineTile2D<?> tile_left = null;
                    AbstractAffineTile2D<?> tile_top = null;
                    final TranslationModel2D tile_model = new TranslationModel2D();
                    // tile_model.getAffine().setTransform( patch[ i ].getAffineTransform() );
                    tile_model.set((float) patch[i].getAffineTransform().getTranslateX(), (float) patch[i].getAffineTransform().getTranslateY());
                    final AbstractAffineTile2D<?> tile = new TranslationTile2D(tile_model, patch[i]);
                    al_tiles.add(tile);
                    // stitch with the one above if starting row
                    if (0 == i % grid_width) {
                        prev_i = i - grid_width;
                        prev = TOP;
                    } else {
                        prev_i = i - 1;
                        prev = LEFT;
                    }
                    if (TOP == prev) {
                        // compare with top only
                        R1 = correlate(patch[prev_i], patch[i], param.overlap, param.cc_scale, TOP_BOTTOM, default_dx, default_dy, param.min_R);
                        R2 = null;
                        tile_top = al_tiles.get(i - grid_width);
                    } else {
                        // the one on the left
                        R2 = correlate(patch[prev_i], patch[i], param.overlap, param.cc_scale, LEFT_RIGHT, default_dx, default_dy, param.min_R);
                        tile_left = al_tiles.get(i - 1);
                        // the one above
                        if (i - grid_width > -1) {
                            R1 = correlate(patch[i - grid_width], patch[i], param.overlap, param.cc_scale, TOP_BOTTOM, default_dx, default_dy, param.min_R);
                            tile_top = al_tiles.get(i - grid_width);
                        } else {
                            R1 = null;
                        }
                    }
                    // boundary limits: don't move by more than the small dimension of the stripe
                    // TODO: only the dx for left (and the dy for top) should be compared and found to be smaller or equal; the other dimension should be unbounded -for example, for manually acquired, grossly out-of-grid tiles.
                    final int max_abs_delta;
                    final Rectangle box = new Rectangle();
                    final Rectangle box2 = new Rectangle();
                    // check and apply: falls back to default overlaps when getting bad results
                    if (TOP == prev) {
                        if (SUCCESS == R1[2]) {
                            // trust top
                            if (optimize)
                                addMatches(tile_top, tile, R1[0], R1[1]);
                            else {
                                patch[i - grid_width].getBoundingBox(box);
                                patch[i].setLocation(box.x + R1[0], box.y + R1[1]);
                            }
                        } else {
                            final Rectangle b2 = patch[i - grid_width].getBoundingBox(null);
                            // don't move: use default overlap
                            if (optimize)
                                addMatches(tile_top, tile, 0, b2.height - default_bottom_top_overlap);
                            else {
                                patch[i - grid_width].getBoundingBox(box);
                                patch[i].setLocation(box.x, box.y + b2.height - default_bottom_top_overlap);
                            }
                        }
                    } else {
                        // the one on top, if any
                        if (i - grid_width > -1) {
                            if (SUCCESS == R1[2]) {
                                // top is good
                                if (SUCCESS == R2[2]) {
                                    // combine left and top
                                    if (optimize) {
                                        addMatches(tile_left, tile, R2[0], R2[1]);
                                        addMatches(tile_top, tile, R1[0], R1[1]);
                                    } else {
                                        patch[i - 1].getBoundingBox(box);
                                        patch[i - grid_width].getBoundingBox(box2);
                                        patch[i].setLocation((box.x + R1[0] + box2.x + R2[0]) / 2, (box.y + R1[1] + box2.y + R2[1]) / 2);
                                    }
                                } else {
                                    // use top alone
                                    if (optimize)
                                        addMatches(tile_top, tile, R1[0], R1[1]);
                                    else {
                                        patch[i - grid_width].getBoundingBox(box);
                                        patch[i].setLocation(box.x + R1[0], box.y + R1[1]);
                                    }
                                }
                            } else {
                                // ignore top
                                if (SUCCESS == R2[2]) {
                                    // use left alone
                                    if (optimize)
                                        addMatches(tile_left, tile, R2[0], R2[1]);
                                    else {
                                        patch[i - 1].getBoundingBox(box);
                                        patch[i].setLocation(box.x + R2[0], box.y + R2[1]);
                                    }
                                } else {
                                    patch[prev_i].getBoundingBox(box);
                                    patch[i - grid_width].getBoundingBox(box2);
                                    // left not trusted, top not trusted: use a combination of defaults for both
                                    if (optimize) {
                                        addMatches(tile_left, tile, box.width - default_left_right_overlap, 0);
                                        addMatches(tile_top, tile, 0, box2.height - default_bottom_top_overlap);
                                    } else {
                                        patch[i].setLocation(box.x + box.width - default_left_right_overlap, box2.y + box2.height - default_bottom_top_overlap);
                                    }
                                }
                            }
                        } else if (SUCCESS == R2[2]) {
                            // use left alone (top not applicable in top row)
                            if (optimize)
                                addMatches(tile_left, tile, R2[0], R2[1]);
                            else {
                                patch[i - 1].getBoundingBox(box);
                                patch[i].setLocation(box.x + R2[0], box.y + R2[1]);
                            }
                        } else {
                            patch[prev_i].getBoundingBox(box);
                            // left not trusted, and top not applicable: use default overlap with left tile
                            if (optimize)
                                addMatches(tile_left, tile, box.width - default_left_right_overlap, 0);
                            else {
                                patch[i].setLocation(box.x + box.width - default_left_right_overlap, box.y);
                            }
                        }
                    }
                    if (!optimize)
                        Display.repaint(patch[i].getLayer(), patch[i], null, 0, false);
                    Utils.log2(i + ": Done patch " + patch[i]);
                }
                if (optimize) {
                    final ArrayList<AbstractAffineTile2D<?>> al_fixed_tiles = new ArrayList<AbstractAffineTile2D<?>>();
                    // Add locked tiles as fixed tiles, if any:
                    for (int i = 0; i < patch.length; i++) {
                        if (patch[i].isLocked2())
                            al_fixed_tiles.add(al_tiles.get(i));
                    }
                    if (al_fixed_tiles.isEmpty()) {
                        // When none, add the first one as fixed
                        al_fixed_tiles.add(al_tiles.get(0));
                    }
                    // Optimize iteratively tile configuration by removing bad matches
                    optimizeTileConfiguration(al_tiles, al_fixed_tiles, param);
                    for (final AbstractAffineTile2D<?> t : al_tiles) t.getPatch().setAffineTransform(t.getModel().createAffine());
                }
                // Remove or hide disconnected tiles
                if (param.hide_disconnected || param.remove_disconnected) {
                    final List<Set<Tile<?>>> graphs = AbstractAffineTile2D.identifyConnectedGraphs(al_tiles);
                    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;
                    Utils.log("Size of largest stitching graph = " + largestGraph.size());
                    interestingTiles = new ArrayList<AbstractAffineTile2D<?>>();
                    for (final Tile<?> t : largestGraph) interestingTiles.add((AbstractAffineTile2D<?>) t);
                    if (param.hide_disconnected)
                        for (final AbstractAffineTile2D<?> t : al_tiles) if (!interestingTiles.contains(t))
                            t.getPatch().setVisible(false);
                    if (param.remove_disconnected)
                        for (final AbstractAffineTile2D<?> t : al_tiles) if (!interestingTiles.contains(t))
                            t.getPatch().remove(false);
                }
                // all
                Display.repaint(patch[0].getLayer(), null, 0, true);
            // 
            } catch (final Exception e) {
                IJError.print(e);
            }
        }
    };
}
Also used : TranslationTile2D(mpicbg.trakem2.align.TranslationTile2D) Set(java.util.Set) AbstractAffineTile2D(mpicbg.trakem2.align.AbstractAffineTile2D) ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) Tile(mpicbg.models.Tile) Point(mpicbg.models.Point) TranslationModel2D(mpicbg.models.TranslationModel2D)

Example 2 with AbstractAffineTile2D

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

the class StitchingTEM method optimizeTileConfiguration.

/**
 * Optimize tile configuration by removing bad matches
 *
 * @param tiles complete list of tiles
 * @param fixed_tiles list of fixed tiles
 * @param param phase correlation parameters
 */
public static void optimizeTileConfiguration(final ArrayList<AbstractAffineTile2D<?>> tiles, final ArrayList<AbstractAffineTile2D<?>> fixed_tiles, final PhaseCorrelationParam param) {
    // Run optimization
    if (fixed_tiles.isEmpty())
        fixed_tiles.add(tiles.get(0));
    // with default parameters
    boolean proceed = true;
    while (proceed) {
        Align.optimizeTileConfiguration(new Align.ParamOptimize(), tiles, fixed_tiles);
        /* get all transfer errors */
        final ErrorStatistic e = new ErrorStatistic(tiles.size() + 1);
        for (final AbstractAffineTile2D<?> t : tiles) t.update();
        for (final AbstractAffineTile2D<?> t : tiles) {
            for (final PointMatch p : t.getMatches()) {
                e.add(p.getDistance());
            }
        }
        /* remove the worst if there is one */
        if (e.max > param.mean_factor * e.mean) {
            A: for (final AbstractAffineTile2D<?> t : tiles) {
                for (final PointMatch p : t.getMatches()) {
                    if (p.getDistance() >= e.max) {
                        final Tile<?> o = t.findConnectedTile(p);
                        t.removeConnectedTile(o);
                        o.removeConnectedTile(t);
                        // Utils.log2( "Removing bad match from configuration, error = " + e.max );
                        break A;
                    }
                }
            }
        } else
            proceed = false;
    }
}
Also used : PointMatch(mpicbg.models.PointMatch) Align(mpicbg.trakem2.align.Align) AbstractAffineTile2D(mpicbg.trakem2.align.AbstractAffineTile2D) ErrorStatistic(mpicbg.models.ErrorStatistic) Tile(mpicbg.models.Tile)

Example 3 with AbstractAffineTile2D

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

the class AlignTask method alignGraphs.

private static final boolean alignGraphs(final Align.Param p, final Layer layer1, final Layer layer2, final Iterable<Tile<?>> graph1, final Iterable<Tile<?>> graph2) {
    final Align.Param cp = p.clone();
    final Selection selection1 = new Selection(null);
    for (final Tile<?> tile : graph1) selection1.add(((AbstractAffineTile2D<?>) tile).getPatch());
    final Rectangle graph1Box = selection1.getBox();
    final Selection selection2 = new Selection(null);
    for (final Tile<?> tile : graph2) selection2.add(((AbstractAffineTile2D<?>) tile).getPatch());
    final Rectangle graph2Box = selection2.getBox();
    final int maxLength = Math.max(Math.max(Math.max(graph1Box.width, graph1Box.height), graph2Box.width), graph2Box.height);
    // final double scale = ( double )cp.sift.maxOctaveSize / maxLength;
    /* rather ad hoc but we cannot just scale this to maxOctaveSize */
    cp.sift.maxOctaveSize = Math.min(maxLength, 2 * p.sift.maxOctaveSize);
    /* make sure that, despite rounding issues from scale, it is >= image size */
    final double scale = (double) (cp.sift.maxOctaveSize - 1) / maxLength;
    // cp.maxEpsilon *= scale;
    final FloatArray2DSIFT sift = new FloatArray2DSIFT(cp.sift);
    final SIFT ijSIFT = new SIFT(sift);
    final ArrayList<Feature> features1 = new ArrayList<Feature>();
    final ArrayList<Feature> features2 = new ArrayList<Feature>();
    final ArrayList<PointMatch> candidates = new ArrayList<PointMatch>();
    final ArrayList<PointMatch> inliers = new ArrayList<PointMatch>();
    long s = System.currentTimeMillis();
    ijSIFT.extractFeatures(layer1.getProject().getLoader().getFlatImage(layer1, graph1Box, scale, 0xffffffff, ImagePlus.GRAY8, Patch.class, selection1.getSelected(Patch.class), false, Color.GRAY).getProcessor(), features1);
    Utils.log(features1.size() + " features extracted for graphs in layer \"" + layer1.getTitle() + "\" (took " + (System.currentTimeMillis() - s) + " ms).");
    ijSIFT.extractFeatures(layer2.getProject().getLoader().getFlatImage(layer2, graph2Box, scale, 0xffffffff, ImagePlus.GRAY8, Patch.class, selection2.getSelected(Patch.class), false, Color.GRAY).getProcessor(), features2);
    Utils.log(features2.size() + " features extracted for graphs in layer \"" + layer1.getTitle() + "\" (took " + (System.currentTimeMillis() - s) + " ms).");
    boolean modelFound = false;
    if (features1.size() > 0 && features2.size() > 0) {
        s = System.currentTimeMillis();
        FeatureTransform.matchFeatures(features1, features2, candidates, cp.rod);
        final AbstractAffineModel2D<?> model;
        switch(cp.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 false;
        }
        boolean again = false;
        try {
            do {
                again = false;
                modelFound = model.filterRansac(candidates, inliers, 1000, cp.maxEpsilon, cp.minInlierRatio, cp.minNumInliers, 3);
                if (modelFound && cp.rejectIdentity) {
                    final ArrayList<Point> points = new ArrayList<Point>();
                    PointMatch.sourcePoints(inliers, points);
                    if (Transforms.isIdentity(model, points, cp.identityTolerance)) {
                        IJ.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 graphs in layer \"" + layer1.getTitle() + "\" and \"" + layer2.getTitle() + "\":\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(graph2Box.x, graph2Box.y);
            b.scale(1.0f / scale, 1.0f / scale);
            b.concatenate(model.createAffine());
            b.scale(scale, scale);
            b.translate(-graph1Box.x, -graph1Box.y);
            for (final Displayable d : selection1.getSelected(Patch.class)) d.getAffineTransform().preConcatenate(b);
            /* assign patch affine transformation to the tile model */
            for (final Tile<?> t : graph1) ((AbstractAffineTile2D<?>) t).initModel();
            Display.repaint(layer1);
        } else
            IJ.log("No model found for graphs in layer \"" + layer1.getTitle() + "\" and \"" + layer2.getTitle() + "\":\n  correspondence candidates  " + candidates.size() + "\n  took " + (System.currentTimeMillis() - s) + " ms");
    }
    return modelFound;
}
Also used : NotEnoughDataPointsException(mpicbg.models.NotEnoughDataPointsException) SIFT(mpicbg.ij.SIFT) FloatArray2DSIFT(mpicbg.imagefeatures.FloatArray2DSIFT) Selection(ini.trakem2.display.Selection) 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) SimilarityModel2D(mpicbg.models.SimilarityModel2D) Displayable(ini.trakem2.display.Displayable) Point(mpicbg.models.Point) 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 4 with AbstractAffineTile2D

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

the class ElasticMontage method exec.

@SuppressWarnings("deprecation")
public final void exec(final Param param, final List<Patch> patches, final Set<Patch> fixedPatches) throws Exception {
    /* free memory */
    patches.get(0).getProject().getLoader().releaseAll();
    /* create tiles and models for all patches */
    final ArrayList<AbstractAffineTile2D<?>> tiles = new ArrayList<AbstractAffineTile2D<?>>();
    final ArrayList<AbstractAffineTile2D<?>> fixedTiles = new ArrayList<AbstractAffineTile2D<?>>();
    Align.tilesFromPatches(param.po, patches, fixedPatches, tiles, fixedTiles);
    if (!param.isAligned) {
        Align.alignTiles(param.po, tiles, fixedTiles, param.tilesAreInPlace, param.maxNumThreads);
        /* Apply the estimated affine transform to patches */
        for (final AbstractAffineTile2D<?> t : tiles) t.getPatch().setAffineTransform(t.createAffine());
        Display.update();
    }
    /* generate tile pairs for all by now overlapping tiles */
    final ArrayList<AbstractAffineTile2D<?>[]> tilePairs = new ArrayList<AbstractAffineTile2D<?>[]>();
    AbstractAffineTile2D.pairOverlappingTiles(tiles, tilePairs);
    /* check if there was any pair */
    if (tilePairs.size() == 0) {
        Utils.log("Elastic montage could not find any overlapping patches after pre-montaging.");
        return;
    }
    Utils.log(tilePairs.size() + " pairs of patches will be block-matched...");
    /* make pairwise global models local */
    final ArrayList<Triple<AbstractAffineTile2D<?>, AbstractAffineTile2D<?>, InvertibleCoordinateTransform>> pairs = new ArrayList<Triple<AbstractAffineTile2D<?>, AbstractAffineTile2D<?>, InvertibleCoordinateTransform>>();
    /*
		 * The following casting madness is necessary to get this code compiled
		 * with Sun/Oracle Java 6 which otherwise generates an inconvertible
		 * type exception.
		 *
		 * TODO Remove as soon as this bug is fixed in Sun/Oracle javac.
		 */
    for (final AbstractAffineTile2D<?>[] pair : tilePairs) {
        final AbstractAffineModel2D<?> m;
        switch(param.po.desiredModelIndex) {
            case 0:
                final TranslationModel2D t = (TranslationModel2D) (Object) pair[1].getModel().createInverse();
                t.concatenate((TranslationModel2D) (Object) pair[0].getModel());
                m = t;
                break;
            case 1:
                final RigidModel2D r = (RigidModel2D) (Object) pair[1].getModel().createInverse();
                r.concatenate((RigidModel2D) (Object) pair[0].getModel());
                m = r;
                break;
            case 2:
                final SimilarityModel2D s = (SimilarityModel2D) (Object) pair[1].getModel().createInverse();
                s.concatenate((SimilarityModel2D) (Object) pair[0].getModel());
                m = s;
                break;
            case 3:
                final AffineModel2D a = (AffineModel2D) (Object) pair[1].getModel().createInverse();
                a.concatenate((AffineModel2D) (Object) pair[0].getModel());
                m = a;
                break;
            default:
                m = null;
        }
        pairs.add(new Triple<AbstractAffineTile2D<?>, AbstractAffineTile2D<?>, InvertibleCoordinateTransform>(pair[0], pair[1], m));
    }
    /* Elastic alignment */
    /* Initialization */
    final double springTriangleHeightTwice = 2 * Math.sqrt(0.75 * param.springLengthSpringMesh * param.springLengthSpringMesh);
    final ArrayList<SpringMesh> meshes = new ArrayList<SpringMesh>(tiles.size());
    final HashMap<AbstractAffineTile2D<?>, SpringMesh> tileMeshMap = new HashMap<AbstractAffineTile2D<?>, SpringMesh>();
    for (final AbstractAffineTile2D<?> tile : tiles) {
        final double w = tile.getWidth();
        final double h = tile.getHeight();
        final int numX = Math.max(2, (int) Math.ceil(w / param.springLengthSpringMesh) + 1);
        final int numY = Math.max(2, (int) Math.ceil(h / springTriangleHeightTwice) + 1);
        final double wMesh = (numX - 1) * param.springLengthSpringMesh;
        final double hMesh = (numY - 1) * springTriangleHeightTwice;
        final SpringMesh mesh = new SpringMesh(numX, numY, wMesh, hMesh, param.stiffnessSpringMesh, param.maxStretchSpringMesh * param.bmScale, param.dampSpringMesh);
        meshes.add(mesh);
        tileMeshMap.put(tile, mesh);
    }
    // final int blockRadius = Math.max( 32, Util.roundPos( param.springLengthSpringMesh / 2 ) );
    final int blockRadius = Math.max(Util.roundPos(16 / param.bmScale), param.bmBlockRadius);
    /**
     * TODO set this something more than the largest error by the approximate model
     */
    final int searchRadius = param.bmSearchRadius;
    final AbstractModel<?> localSmoothnessFilterModel = mpicbg.trakem2.align.Util.createModel(param.bmLocalModelIndex);
    for (final Triple<AbstractAffineTile2D<?>, AbstractAffineTile2D<?>, InvertibleCoordinateTransform> pair : pairs) {
        final AbstractAffineTile2D<?> t1 = pair.a;
        final AbstractAffineTile2D<?> t2 = pair.b;
        final SpringMesh m1 = tileMeshMap.get(t1);
        final SpringMesh m2 = tileMeshMap.get(t2);
        final ArrayList<PointMatch> pm12 = new ArrayList<PointMatch>();
        final ArrayList<PointMatch> pm21 = new ArrayList<PointMatch>();
        final ArrayList<Vertex> v1 = m1.getVertices();
        final ArrayList<Vertex> v2 = m2.getVertices();
        final String patchName1 = patchName(t1.getPatch());
        final String patchName2 = patchName(t2.getPatch());
        final PatchImage pi1 = t1.getPatch().createTransformedImage();
        if (pi1 == null) {
            Utils.log("Patch `" + patchName1 + "' failed generating a transformed image.  Skipping...");
            continue;
        }
        final PatchImage pi2 = t2.getPatch().createTransformedImage();
        if (pi2 == null) {
            Utils.log("Patch `" + patchName2 + "' failed generating a transformed image.  Skipping...");
            continue;
        }
        final FloatProcessor fp1 = (FloatProcessor) pi1.target.convertToFloat();
        final ByteProcessor mask1 = pi1.getMask();
        final FloatProcessor fpMask1 = mask1 == null ? null : scaleByte(mask1);
        final FloatProcessor fp2 = (FloatProcessor) pi2.target.convertToFloat();
        final ByteProcessor mask2 = pi2.getMask();
        final FloatProcessor fpMask2 = mask2 == null ? null : scaleByte(mask2);
        if (!fixedTiles.contains(t1)) {
            BlockMatching.matchByMaximalPMCC(fp1, fp2, fpMask1, fpMask2, param.bmScale, pair.c, blockRadius, blockRadius, searchRadius, searchRadius, param.bmMinR, param.bmRodR, param.bmMaxCurvatureR, v1, pm12, new ErrorStatistic(1));
            if (param.bmUseLocalSmoothnessFilter) {
                Utils.log("`" + patchName1 + "' > `" + patchName2 + "': found " + pm12.size() + " correspondence candidates.");
                localSmoothnessFilterModel.localSmoothnessFilter(pm12, pm12, param.bmLocalRegionSigma, param.bmMaxLocalEpsilon, param.bmMaxLocalTrust);
                Utils.log("`" + patchName1 + "' > `" + patchName2 + "': " + pm12.size() + " candidates passed local smoothness filter.");
            } else {
                Utils.log("`" + patchName1 + "' > `" + patchName2 + "': found " + pm12.size() + " correspondences.");
            }
        } else {
            Utils.log("Skipping fixed patch `" + patchName1 + "'.");
        }
        if (!fixedTiles.contains(t2)) {
            BlockMatching.matchByMaximalPMCC(fp2, fp1, fpMask2, fpMask1, param.bmScale, pair.c.createInverse(), blockRadius, blockRadius, searchRadius, searchRadius, param.bmMinR, param.bmRodR, param.bmMaxCurvatureR, v2, pm21, new ErrorStatistic(1));
            if (param.bmUseLocalSmoothnessFilter) {
                Utils.log("`" + patchName1 + "' < `" + patchName2 + "': found " + pm21.size() + " correspondence candidates.");
                localSmoothnessFilterModel.localSmoothnessFilter(pm21, pm21, param.bmLocalRegionSigma, param.bmMaxLocalEpsilon, param.bmMaxLocalTrust);
                Utils.log("`" + patchName1 + "' < `" + patchName2 + "': " + pm21.size() + " candidates passed local smoothness filter.");
            } else {
                Utils.log("`" + patchName1 + "' < `" + patchName2 + "': found " + pm21.size() + " correspondences.");
            }
        } else {
            Utils.log("Skipping fixed patch `" + patchName2 + "'.");
        }
        for (final PointMatch pm : pm12) {
            final Vertex p1 = (Vertex) pm.getP1();
            final Vertex p2 = new Vertex(pm.getP2());
            p1.addSpring(p2, new Spring(0, 1.0f));
            m2.addPassiveVertex(p2);
        }
        for (final PointMatch pm : pm21) {
            final Vertex p1 = (Vertex) pm.getP1();
            final Vertex p2 = new Vertex(pm.getP2());
            p1.addSpring(p2, new Spring(0, 1.0f));
            m1.addPassiveVertex(p2);
        }
    }
    /* initialize */
    for (final Map.Entry<AbstractAffineTile2D<?>, SpringMesh> entry : tileMeshMap.entrySet()) entry.getValue().init(entry.getKey().getModel());
    /* optimize the meshes */
    try {
        final long t0 = System.currentTimeMillis();
        IJ.log("Optimizing spring meshes...");
        if (param.useLegacyOptimizer) {
            Utils.log("  ...using legacy optimizer...");
            SpringMesh.optimizeMeshes2(meshes, param.po.maxEpsilon, param.maxIterationsSpringMesh, param.maxPlateauwidthSpringMesh, param.visualize);
        } else {
            SpringMesh.optimizeMeshes(meshes, param.po.maxEpsilon, param.maxIterationsSpringMesh, param.maxPlateauwidthSpringMesh, param.visualize);
        }
        IJ.log("Done optimizing spring meshes. Took " + (System.currentTimeMillis() - t0) + " ms");
    } catch (final NotEnoughDataPointsException e) {
        Utils.log("There were not enough data points to get the spring mesh optimizing.");
        e.printStackTrace();
        return;
    }
    /* apply */
    for (final Map.Entry<AbstractAffineTile2D<?>, SpringMesh> entry : tileMeshMap.entrySet()) {
        final AbstractAffineTile2D<?> tile = entry.getKey();
        if (!fixedTiles.contains(tile)) {
            final Patch patch = tile.getPatch();
            final SpringMesh mesh = entry.getValue();
            final Set<PointMatch> matches = mesh.getVA().keySet();
            Rectangle box = patch.getCoordinateTransformBoundingBox();
            /* compensate for existing coordinate transform bounding box */
            for (final PointMatch pm : matches) {
                final Point p1 = pm.getP1();
                final double[] l = p1.getL();
                l[0] += box.x;
                l[1] += box.y;
            }
            final ThinPlateSplineTransform mlt = ElasticLayerAlignment.makeTPS(matches);
            patch.appendCoordinateTransform(mlt);
            box = patch.getCoordinateTransformBoundingBox();
            patch.getAffineTransform().setToTranslation(box.x, box.y);
            patch.updateInDatabase("transform");
            patch.updateBucket();
            patch.updateMipMaps();
        }
    }
    Utils.log("Done.");
}
Also used : ByteProcessor(ij.process.ByteProcessor) NotEnoughDataPointsException(mpicbg.models.NotEnoughDataPointsException) Vertex(mpicbg.models.Vertex) SpringMesh(mpicbg.models.SpringMesh) ThinPlateSplineTransform(mpicbg.trakem2.transform.ThinPlateSplineTransform) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) RigidModel2D(mpicbg.models.RigidModel2D) AbstractAffineModel2D(mpicbg.models.AbstractAffineModel2D) AffineModel2D(mpicbg.models.AffineModel2D) SimilarityModel2D(mpicbg.models.SimilarityModel2D) FloatProcessor(ij.process.FloatProcessor) Point(mpicbg.models.Point) Spring(mpicbg.models.Spring) Point(mpicbg.models.Point) Triple(mpicbg.trakem2.util.Triple) PointMatch(mpicbg.models.PointMatch) PatchImage(ini.trakem2.display.Patch.PatchImage) InvertibleCoordinateTransform(mpicbg.models.InvertibleCoordinateTransform) ErrorStatistic(mpicbg.models.ErrorStatistic) TranslationModel2D(mpicbg.models.TranslationModel2D) HashMap(java.util.HashMap) Map(java.util.Map) Patch(ini.trakem2.display.Patch)

Example 5 with AbstractAffineTile2D

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

the class Align method fetchPointMatches.

/**
 * Fetch a {@link Collection} of corresponding
 * {@link Feature SIFT-features}.  Both {@link Feature SIFT-features} and
 * {@linkplain PointMatch corresponding points} are cached to disk.
 *
 * @param p
 * @param t1
 * @param t2
 * @return
 *   <dl>
 *     <dt>null</dt><dd>if matching failed for some reasons</dd>
 *     <dt>empty {@link Collection}</dt><dd>if there was no consistent set
 *       of {@link PointMatch matches}</dd>
 *     <dt>{@link Collection} of {@link PointMatch PointMatches}</dt>
 *       <dd>if there was a consistent set of {@link PointMatch
 *         PointMatches}</dd>
 *   </dl>
 */
protected static final Collection<PointMatch> fetchPointMatches(final Param p, final AbstractAffineTile2D<?> t1, final AbstractAffineTile2D<?> t2) {
    final Collection<PointMatch> pointMatches = deserializePointMatches(p, t1, t2);
    if (pointMatches == null) {
        final List<PointMatch> candidates = new ArrayList<PointMatch>();
        final List<PointMatch> inliers = new ArrayList<PointMatch>();
        final long s = System.currentTimeMillis();
        FeatureTransform.matchFeatures(fetchFeatures(p, t1), fetchFeatures(p, t2), 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 null;
        }
        final boolean modelFound = findModel(model, candidates, inliers, p.maxEpsilon, p.minInlierRatio, p.minNumInliers, p.rejectIdentity, p.identityTolerance);
        if (modelFound)
            Utils.log("Model found for tiles \"" + t1.getPatch() + "\" and \"" + t2.getPatch() + "\":\n  correspondences  " + inliers.size() + " of " + candidates.size() + "\n  average residual error  " + model.getCost() + " px\n  took " + (System.currentTimeMillis() - s) + " ms");
        else
            Utils.log("No model found for tiles \"" + t1.getPatch() + "\" and \"" + t2.getPatch() + "\":\n  correspondence candidates  " + candidates.size() + "\n  took " + (System.currentTimeMillis() - s) + " ms");
        if (!serializePointMatches(p, t1, t2, pointMatches))
            Utils.log("Saving point matches failed for tile \"" + t1.getPatch() + "\" and tile \"" + t2.getPatch() + "\"");
    }
    return pointMatches;
}
Also used : PointMatch(mpicbg.models.PointMatch) RigidModel2D(mpicbg.trakem2.transform.RigidModel2D) ArrayList(java.util.ArrayList) AbstractAffineModel2D(mpicbg.models.AbstractAffineModel2D) AffineModel2D(mpicbg.models.AffineModel2D) InterpolatedAffineModel2D(mpicbg.models.InterpolatedAffineModel2D) TranslationModel2D(mpicbg.trakem2.transform.TranslationModel2D) SimilarityModel2D(mpicbg.models.SimilarityModel2D)

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