Search in sources :

Example 16 with CoordinateTransform

use of mpicbg.trakem2.transform.CoordinateTransform in project TrakEM2 by trakem2.

the class Patch method addAlphaMaskLocal.

/**
 * Add the given area, in local coordinates, to the alpha mask, using the given fill value.
 */
public void addAlphaMaskLocal(final Area aLocal, int value) {
    if (value < 0)
        value = 0;
    if (value > 255)
        value = 255;
    // 
    CoordinateTransform ct = null;
    if (hasCoordinateTransform() && null == (ct = getCT())) {
        return;
    }
    // When the area is larger than the image, sometimes the area fails to be set at all
    // Also, intersection accelerates calls to contains(x,y) for complex polygons
    final Area a = new Area(new Rectangle(0, 0, (int) (width + 1), (int) (height + 1)));
    a.intersect(aLocal);
    if (M.isEmpty(a)) {
        Utils.log("ROI does not intersect the active image!");
        return;
    }
    ByteProcessor mask = getAlphaMask();
    // Use imglib to bypass all the problems with ShapeROI
    // Create a Shape image with background and the Area on it with 'value'
    final int background = (null != mask && 255 == value) ? 0 : 255;
    final ShapeList<UnsignedByteType> shapeList = new ShapeList<UnsignedByteType>(new int[] { (int) width, (int) height, 1 }, new UnsignedByteType(background));
    shapeList.addShape(a, new UnsignedByteType(value), new int[] { 0 });
    final mpicbg.imglib.image.Image<UnsignedByteType> shapeListImage = new mpicbg.imglib.image.Image<UnsignedByteType>(shapeList, shapeList.getBackground(), "mask");
    ByteProcessor rmask = (ByteProcessor) ImageJFunctions.copyToImagePlus(shapeListImage, ImagePlus.GRAY8).getProcessor();
    if (hasCoordinateTransform()) {
        // inverse the coordinate transform
        final TransformMesh mesh = new TransformMesh(ct, meshResolution, o_width, o_height);
        final TransformMeshMapping mapping = new TransformMeshMapping(mesh);
        rmask = (ByteProcessor) mapping.createInverseMappedImageInterpolated(rmask);
    }
    if (null == mask) {
        // There wasn't a mask, hence just set it
        mask = rmask;
    } else {
        final byte[] b1 = (byte[]) mask.getPixels();
        final byte[] b2 = (byte[]) rmask.getPixels();
        // Whatever is not background in the new mask gets set on the old mask
        for (int i = 0; i < b1.length; i++) {
            // background pixel in new mask
            if (background == (b2[i] & 0xff))
                continue;
            // replace old pixel with new pixel
            b1[i] = b2[i];
        }
    }
    setAlphaMask(mask);
}
Also used : ByteProcessor(ij.process.ByteProcessor) TransformMeshMapping(mpicbg.trakem2.transform.TransformMeshMapping) UnsignedByteType(mpicbg.imglib.type.numeric.integer.UnsignedByteType) ShapeList(mpicbg.imglib.container.shapelist.ShapeList) Rectangle(java.awt.Rectangle) Image(java.awt.Image) BufferedImage(java.awt.image.BufferedImage) ExportBestFlatImage(mpicbg.trakem2.transform.ExportBestFlatImage) Area(java.awt.geom.Area) CoordinateTransform(mpicbg.trakem2.transform.CoordinateTransform) TransformMesh(mpicbg.trakem2.transform.TransformMesh) CoordinateTransformMesh(mpicbg.models.CoordinateTransformMesh)

Example 17 with CoordinateTransform

use of mpicbg.trakem2.transform.CoordinateTransform in project TrakEM2 by trakem2.

the class Patch method getLocalAffine.

/**
 * Return the local affine transformation for a passed location in world
 * coordinates.   This affine transform is either the global affine
 * transform of the patch or the combined affine transform of the local
 * affine transform in the transform mesh and its global affine transform.
 *
 * @param wx
 * @param wy
 * @return
 */
public AffineTransform getLocalAffine(final double wx, final double wy) {
    final AffineTransform affine = new AffineTransform(at);
    if (hasCoordinateTransform()) {
        final CoordinateTransform ct = getCoordinateTransform();
        final double[] w = new double[] { wx, wy };
        try {
            at.inverseTransform(w, 0, w, 0, 1);
        } catch (final NoninvertibleTransformException e) {
        }
        final TransformMesh mesh = new TransformMesh(ct, meshResolution, o_width, o_height);
        final mpicbg.models.AffineModel2D triangle = mesh.closestTargetAffine(new double[] { w[0], w[1] });
        affine.concatenate(triangle.createAffine());
    }
    return affine;
}
Also used : NoninvertibleTransformException(java.awt.geom.NoninvertibleTransformException) AffineTransform(java.awt.geom.AffineTransform) CoordinateTransform(mpicbg.trakem2.transform.CoordinateTransform) TransformMesh(mpicbg.trakem2.transform.TransformMesh) CoordinateTransformMesh(mpicbg.models.CoordinateTransformMesh)

Example 18 with CoordinateTransform

use of mpicbg.trakem2.transform.CoordinateTransform in project TrakEM2 by trakem2.

the class Patch method createCoordinateTransformedImage.

public final Patch.PatchImage createCoordinateTransformedImage() {
    if (!hasCoordinateTransform())
        return null;
    final CoordinateTransform ct = getCoordinateTransform();
    final ImageProcessor source = getImageProcessor();
    // some error occurred
    if (null == source)
        return null;
    // Utils.log2("source image dimensions: " + source.getWidth() + ", " + source.getHeight());
    final TransformMesh mesh = new TransformMesh(ct, meshResolution, o_width, o_height);
    final Rectangle box = mesh.getBoundingBox();
    /* We can calculate the exact size of the image to be rendered, so let's do it */
    // project.getLoader().releaseToFit(o_width, o_height, type, 5);
    final long b = // outside and mask source
    2 * o_width * o_height + // outside and mask target
    2 * box.width * box.height + // image source
    5 * o_width * o_height + // image target
    5 * box.width * box.height;
    project.getLoader().releaseToFit(b);
    final TransformMeshMapping mapping = new TransformMeshMapping(mesh);
    final ImageProcessorWithMasks target = mapping.createMappedMaskedImageInterpolated(source, getAlphaMask());
    // Set the LUT
    target.ip.setColorModel(source.getColorModel());
    return new PatchImage(target.ip, (ByteProcessor) target.mask, target.outside, box, true);
}
Also used : ImageProcessor(ij.process.ImageProcessor) TransformMeshMapping(mpicbg.trakem2.transform.TransformMeshMapping) ImageProcessorWithMasks(mpicbg.trakem2.transform.TransformMeshMappingWithMasks.ImageProcessorWithMasks) Rectangle(java.awt.Rectangle) CoordinateTransform(mpicbg.trakem2.transform.CoordinateTransform) TransformMesh(mpicbg.trakem2.transform.TransformMesh) CoordinateTransformMesh(mpicbg.models.CoordinateTransformMesh)

Example 19 with CoordinateTransform

use of mpicbg.trakem2.transform.CoordinateTransform 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 20 with CoordinateTransform

use of mpicbg.trakem2.transform.CoordinateTransform in project TrakEM2 by trakem2.

the class AlignTask method transformVectorData.

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

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

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

						tlist.add(new InverseICT(old));

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

Aggregations

CoordinateTransform (mpicbg.trakem2.transform.CoordinateTransform)18 CoordinateTransformList (mpicbg.trakem2.transform.CoordinateTransformList)13 Rectangle (java.awt.Rectangle)12 CoordinateTransformMesh (mpicbg.models.CoordinateTransformMesh)10 AffineTransform (java.awt.geom.AffineTransform)9 AffineModel2D (mpicbg.trakem2.transform.AffineModel2D)7 ImageProcessor (ij.process.ImageProcessor)6 NotEnoughDataPointsException (mpicbg.models.NotEnoughDataPointsException)6 Point (mpicbg.models.Point)6 TransformMesh (mpicbg.trakem2.transform.TransformMesh)6 Area (java.awt.geom.Area)5 NoninvertibleTransformException (java.awt.geom.NoninvertibleTransformException)5 ArrayList (java.util.ArrayList)5 AbstractAffineModel2D (mpicbg.models.AbstractAffineModel2D)5 AffineModel2D (mpicbg.models.AffineModel2D)5 NoninvertibleModelException (mpicbg.models.NoninvertibleModelException)5 TransformMeshMapping (mpicbg.trakem2.transform.TransformMeshMapping)5 Layer (ini.trakem2.display.Layer)4 Patch (ini.trakem2.display.Patch)4 ImagePlus (ij.ImagePlus)3