use of mpicbg.models.Tile 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;
}
use of mpicbg.models.Tile in project TrakEM2 by trakem2.
the class RegularizedAffineLayerAlignment method exec.
/**
* @param param
* @param layerRange
* @param fixedLayers
* @param emptyLayers
* @param box
* @param propagateTransformAfter
* @param filter
* @throws Exception
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public final void exec(final Param param, final List<Layer> layerRange, final Set<Layer> fixedLayers, final Set<Layer> emptyLayers, final Rectangle box, final boolean propagateTransformBefore, final boolean propagateTransformAfter, final Filter<Patch> filter) throws Exception {
final double scale = Math.min(1.0, Math.min((double) param.ppm.sift.maxOctaveSize / (double) box.width, (double) param.ppm.sift.maxOctaveSize / (double) box.height));
final ExecutorService exec = ExecutorProvider.getExecutorService(1.0f / (float) param.maxNumThreads);
/* create tiles and models for all layers */
final ArrayList<Tile<?>> tiles = new ArrayList<Tile<?>>();
final AbstractAffineModel2D<?> m = (AbstractAffineModel2D<?>) Util.createModel(param.desiredModelIndex);
final AbstractAffineModel2D<?> r = (AbstractAffineModel2D<?>) Util.createModel(param.regularizerIndex);
for (int i = 0; i < layerRange.size(); ++i) {
if (param.regularize)
tiles.add(new Tile(new InterpolatedAffineModel2D(m.copy(), r.copy(), param.lambda)));
else
tiles.add(new Tile(m.copy()));
}
/* collect all pairs of slices for which a model could be found */
final ArrayList<Triple<Integer, Integer, Collection<PointMatch>>> pairs = new ArrayList<Triple<Integer, Integer, Collection<PointMatch>>>();
/* extract and save features, overwrite cached files if requested */
try {
AlignmentUtils.extractAndSaveLayerFeatures(layerRange, box, scale, filter, param.ppm.sift, param.ppm.clearCache, param.ppm.maxNumThreadsSift);
} catch (final Exception e) {
e.printStackTrace();
IJError.print(e);
return;
}
/* match and filter feature correspondences */
int numFailures = 0, lastA = 0;
final double pointMatchScale = 1.0 / scale;
final ArrayList<Future<Triple<Integer, Integer, Collection<PointMatch>>>> modelFutures = new ArrayList<Future<Triple<Integer, Integer, Collection<PointMatch>>>>();
for (int i = 0; i < layerRange.size(); ++i) {
final int range = Math.min(layerRange.size(), i + param.maxNumNeighbors + 1);
for (int j = i + 1; j < range; ++j) {
modelFutures.add(exec.submit(new CorrespondenceCallable(param, layerRange.get(i), layerRange.get(j), pointMatchScale, i, j)));
}
}
// Assume that futures are ordered in Triple.a
try {
for (final Future<Triple<Integer, Integer, Collection<PointMatch>>> future : modelFutures) {
final Triple<Integer, Integer, Collection<PointMatch>> pair = future.get();
if (lastA != pair.a) {
numFailures = 0;
lastA = pair.a;
}
if (pair.c == null) {
numFailures++;
// TODO: Cancel futures associated with pair.a
} else if (numFailures < param.maxNumFailures) {
pairs.add(pair);
}
}
} catch (final InterruptedException ie) {
Utils.log("Establishing feature correspondences interrupted.");
for (final Future<Triple<Integer, Integer, Collection<PointMatch>>> future : modelFutures) {
future.cancel(true);
}
return;
}
/* collect successfully matches pairs and break the search on gaps */
/*
for ( int t = 0; t < models.size(); ++t )
{
final Triple< Integer, Integer, Collection< PointMatch > > pair = models.get( t );
if ( pair == null )
{
if ( ++numFailures > param.maxNumFailures )
break J;
}
else
{
numFailures = 0;
pairs.add( pair );
}
}
*/
/* Optimization */
final TileConfiguration tileConfiguration = new TileConfiguration();
for (final Triple<Integer, Integer, Collection<PointMatch>> pair : pairs) {
final Tile<?> t1 = tiles.get(pair.a);
final Tile<?> t2 = tiles.get(pair.b);
tileConfiguration.addTile(t1);
tileConfiguration.addTile(t2);
t2.connect(t1, pair.c);
}
for (int i = 0; i < layerRange.size(); ++i) {
final Layer layer = layerRange.get(i);
if (fixedLayers.contains(layer))
tileConfiguration.fixTile(tiles.get(i));
}
final List<Tile<?>> nonPreAlignedTiles = tileConfiguration.preAlign();
IJ.log("pre-aligned all but " + nonPreAlignedTiles.size() + " tiles");
tileConfiguration.optimize(param.maxEpsilon, param.maxIterationsOptimize, param.maxPlateauwidthOptimize);
Utils.log(new StringBuffer("Successfully optimized configuration of ").append(tiles.size()).append(" tiles:").toString());
Utils.log(" average displacement: " + String.format("%.3f", tileConfiguration.getError()) + "px");
Utils.log(" minimal displacement: " + String.format("%.3f", tileConfiguration.getMinError()) + "px");
Utils.log(" maximal displacement: " + String.format("%.3f", tileConfiguration.getMaxError()) + "px");
if (propagateTransformBefore || propagateTransformAfter) {
final Layer first = layerRange.get(0);
final List<Layer> layers = first.getParent().getLayers();
if (propagateTransformBefore) {
final AffineTransform b = translateAffine(box, ((Affine2D<?>) tiles.get(0).getModel()).createAffine());
final int firstLayerIndex = first.getParent().getLayerIndex(first.getId());
for (int i = 0; i < firstLayerIndex; ++i) applyTransformToLayer(layers.get(i), b, filter);
}
if (propagateTransformAfter) {
final Layer last = layerRange.get(layerRange.size() - 1);
final AffineTransform b = translateAffine(box, ((Affine2D<?>) tiles.get(tiles.size() - 1).getModel()).createAffine());
final int lastLayerIndex = last.getParent().getLayerIndex(last.getId());
for (int i = lastLayerIndex + 1; i < layers.size(); ++i) applyTransformToLayer(layers.get(i), b, filter);
}
}
for (int i = 0; i < layerRange.size(); ++i) {
final AffineTransform b = translateAffine(box, ((Affine2D<?>) tiles.get(i).getModel()).createAffine());
applyTransformToLayer(layerRange.get(i), b, filter);
}
Utils.log("Done.");
}
use of mpicbg.models.Tile in project TrakEM2 by trakem2.
the class MatchIntensities method generateCoefficientsTiles.
protected static final <T extends Model<T> & Affine1D<T>> HashMap<Patch, ArrayList<Tile<T>>> generateCoefficientsTiles(final Collection<Patch> patches, final T template, final int nCoefficients) {
final HashMap<Patch, ArrayList<Tile<T>>> map = new HashMap<Patch, ArrayList<Tile<T>>>();
for (final Patch p : patches) {
final ArrayList<Tile<T>> coefficientModels = new ArrayList<Tile<T>>();
for (int i = 0; i < nCoefficients; ++i) coefficientModels.add(new Tile<T>(template.copy()));
map.put(p, coefficientModels);
}
return map;
}
Aggregations