Search in sources :

Example 1 with Montage

use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.

the class PatchStack method createColor256Copy.

// WARNING This method will fail if the stack has slices of different dimensions
/**
 * Does not respect local transform of the patches, this is intended for confocal stacks.
 */
public ImagePlus createColor256Copy() {
    final Rectangle box = patch[0].getBoundingBox();
    final int width = box.width;
    final int height = box.height;
    Loader loader = patch[0].getProject().getLoader();
    // the montage, in RGB
    patch[0].getProject().getLoader().releaseToFit(4 * patch.length * width * height);
    final ColorProcessor montage = new ColorProcessor(width * patch.length, height);
    for (int i = 0; i < patch.length; i++) {
        montage.insert(this.stack.getProcessor(i + 1), i * width, 0);
    }
    final MedianCut mc = new MedianCut(montage);
    loader.releaseToFit(patch.length * width * height);
    ImageProcessor m2 = mc.convertToByte(256);
    final ImageStack st = new ImageStack(width, height);
    for (int i = 0; i < patch.length; i++) {
        m2.setRoi(i * width, 0, width, height);
        loader.releaseToFit(width * height);
        st.addSlice(null, m2.crop());
    }
    ImagePlus imp = new ImagePlus("color256", st);
    imp.setCalibration(patch[0].getLayer().getParent().getCalibrationCopy());
    // imp.getCalibration().pixelDepth = patch[0].getLayer().getThickness();
    return imp;
}
Also used : ImageProcessor(ij.process.ImageProcessor) ColorProcessor(ij.process.ColorProcessor) ImageStack(ij.ImageStack) Rectangle(java.awt.Rectangle) Loader(ini.trakem2.persistence.Loader) MedianCut(ij.process.MedianCut) ImagePlus(ij.ImagePlus)

Example 2 with Montage

use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.

the class AlignTask method alignPatches.

/**
 * @param patches: the list of Patch instances to align, all belonging to the same Layer.
 * @param fixedPatches: the list of Patch instances to keep locked in place, if any.
 * @param m: {@link AlignTask#LINEAR_SIFT_CORRESPONDENCES}, {@link AlignTask#LINEAR_PHASE_CORRELATION} or {@link AlignTask#ELASTIC_BLOCK_CORRESPONDENCES}.
 */
public static final void alignPatches(final List<Patch> patches, final Set<Patch> fixedPatches, final int m) throws Exception {
    if (patches.size() < 2) {
        Utils.log("No images to align.");
        return;
    }
    for (final Patch patch : fixedPatches) {
        if (!patches.contains(patch)) {
            Utils.log("The list of fixed patches contains at least one Patch not included in the list of patches to align!");
            return;
        }
    }
    if (ELASTIC_BLOCK_CORRESPONDENCES == m)
        new ElasticMontage().exec(patches, fixedPatches);
    else if (LINEAR_PHASE_CORRELATION == m) {
        // Montage all given patches, fixedPatches is ignored!
        if (!fixedPatches.isEmpty())
            Utils.log("Ignoring " + fixedPatches.size() + " fixed patches.");
        StitchingTEM.montageWithPhaseCorrelation(patches);
    } else if (LINEAR_SIFT_CORRESPONDENCES == m) {
        if (!Align.paramOptimize.setup("Montage Selection"))
            return;
        final GenericDialog gd = new GenericDialog("Montage Selection: Miscellaneous");
        gd.addCheckbox("tiles are roughly in place", tilesAreInPlace);
        gd.addCheckbox("sloppy overlap test (fast)", sloppyOverlapTest);
        gd.addCheckbox("consider largest graph only", largestGraphOnly);
        gd.addCheckbox("hide tiles from non-largest graph", hideDisconnectedTiles);
        gd.addCheckbox("delete tiles from non-largest graph", deleteDisconnectedTiles);
        gd.showDialog();
        if (gd.wasCanceled())
            return;
        tilesAreInPlace = gd.getNextBoolean();
        sloppyOverlapTest = gd.getNextBoolean();
        largestGraphOnly = gd.getNextBoolean();
        hideDisconnectedTiles = gd.getNextBoolean();
        deleteDisconnectedTiles = gd.getNextBoolean();
        final Align.ParamOptimize p = Align.paramOptimize.clone();
        alignPatches(p, patches, fixedPatches, tilesAreInPlace, largestGraphOnly, hideDisconnectedTiles, deleteDisconnectedTiles, sloppyOverlapTest);
    } else
        Utils.log("Don't know how to align with mode " + m);
}
Also used : GenericDialog(ij.gui.GenericDialog) Patch(ini.trakem2.display.Patch)

Example 3 with Montage

use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.

the class AlignTask method montageLayersTask.

/**
 * Montage each layer independently.
 *  Does NOT register layers to each other.
 *  Considers visible Patches only.
 */
public static final Bureaucrat montageLayersTask(final List<Layer> layers) {
    if (null == layers || layers.isEmpty())
        return null;
    return Bureaucrat.createAndStart(new Worker.Task("Montaging layers", true) {

        @Override
        public void exec() {
            final int m = chooseAlignmentMode();
            if (ELASTIC_BLOCK_CORRESPONDENCES == m) {
                final ElasticMontage.Param p = ElasticMontage.setup();
                if (p == null)
                    return;
                else {
                    try {
                        montageLayers(p, layers);
                    } catch (final Exception e) {
                        e.printStackTrace();
                        Utils.log("Exception during montaging layers.  Operation failed.");
                    }
                }
            } else if (LINEAR_PHASE_CORRELATION == m) {
                StitchingTEM.montageWithPhaseCorrelation(layers, this);
            } else if (LINEAR_SIFT_CORRESPONDENCES == m) {
                if (!Align.paramOptimize.setup("Montage Layers"))
                    return;
                final GenericDialog gd = new GenericDialog("Montage Layers: Miscellaneous");
                gd.addCheckbox("tiles are roughly in place", tilesAreInPlace);
                gd.addCheckbox("sloppy overlap test (fast)", sloppyOverlapTest);
                gd.addCheckbox("consider largest graph only", largestGraphOnly);
                gd.addCheckbox("hide tiles from non-largest graph", hideDisconnectedTiles);
                gd.addCheckbox("delete tiles from non-largest graph", deleteDisconnectedTiles);
                gd.showDialog();
                if (gd.wasCanceled())
                    return;
                tilesAreInPlace = gd.getNextBoolean();
                sloppyOverlapTest = gd.getNextBoolean();
                largestGraphOnly = gd.getNextBoolean();
                hideDisconnectedTiles = gd.getNextBoolean();
                deleteDisconnectedTiles = gd.getNextBoolean();
                final Align.ParamOptimize p = Align.paramOptimize.clone();
                montageLayers(p, layers, tilesAreInPlace, largestGraphOnly, hideDisconnectedTiles, deleteDisconnectedTiles, sloppyOverlapTest);
            } else
                Utils.log("Don't know how to align with mode " + m);
        }
    }, layers.get(0).getProject());
}
Also used : GenericDialog(ij.gui.GenericDialog) Worker(ini.trakem2.utils.Worker) NotEnoughDataPointsException(mpicbg.models.NotEnoughDataPointsException) NoninvertibleModelException(mpicbg.models.NoninvertibleModelException) NoninvertibleTransformException(java.awt.geom.NoninvertibleTransformException)

Example 4 with Montage

use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.

the class ElasticMontage method exec.

public final void exec(final List<Patch> patches, final Set<Patch> fixedPatches) throws Exception {
    /* make sure that passed patches are ok */
    if (patches.size() < 2) {
        Utils.log("Elastic montage requires at least 2 patches to be montaged.  You passed me " + patches.size());
        return;
    }
    final Project project = patches.get(0).getProject();
    for (final Patch patch : patches) {
        if (patch.getProject() != project) {
            Utils.log("Elastic montage requires all patches to be member of a single project.  You passed me patches from several projects.");
            return;
        }
    }
    for (final Patch patch : fixedPatches) {
        if (patch.getProject() != project) {
            Utils.log("Elastic montage requires all fixed patches to be member of a single project.  You passed me fixed patches from several projects.");
            return;
        }
    }
    final Param param = setup();
    if (param == null)
        return;
    else
        exec(param, patches, fixedPatches);
}
Also used : Project(ini.trakem2.Project) Patch(ini.trakem2.display.Patch)

Example 5 with Montage

use of ini.trakem2.utils.Montage 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)

Aggregations

GenericDialog (ij.gui.GenericDialog)7 Patch (ini.trakem2.display.Patch)7 Rectangle (java.awt.Rectangle)6 ArrayList (java.util.ArrayList)6 Worker (ini.trakem2.utils.Worker)5 ImagePlus (ij.ImagePlus)4 File (java.io.File)4 Roi (ij.gui.Roi)3 Project (ini.trakem2.Project)3 NoninvertibleTransformException (java.awt.geom.NoninvertibleTransformException)3 Point (mpicbg.models.Point)3 PolygonRoi (ij.gui.PolygonRoi)2 ShapeRoi (ij.gui.ShapeRoi)2 Displayable (ini.trakem2.display.Displayable)2 Layer (ini.trakem2.display.Layer)2 InspectPatchTrianglesMode (ini.trakem2.display.inspect.InspectPatchTrianglesMode)2 DBObject (ini.trakem2.persistence.DBObject)2 ProjectThing (ini.trakem2.tree.ProjectThing)2 Bureaucrat (ini.trakem2.utils.Bureaucrat)2 Color (java.awt.Color)2