use of mpicbg.trakem2.align.AbstractAffineTile2D in project TrakEM2 by trakem2.
the class DistortionCorrectionTask method run.
public static final void run(final CorrectDistortionFromSelectionParam p, final List<Patch> patches, final Displayable active, final Layer layer, final Worker worker) {
/* no multiple inheritance, so p cannot be an Align.ParamOptimize, working around legacy by copying data into one ... */
final Align.ParamOptimize ap = new Align.ParamOptimize();
ap.sift.set(p.sift);
ap.desiredModelIndex = p.desiredModelIndex;
ap.expectedModelIndex = p.expectedModelIndex;
ap.maxEpsilon = p.maxEpsilon;
ap.minInlierRatio = p.minInlierRatio;
ap.rod = p.rod;
ap.identityTolerance = p.identityTolerance;
ap.lambda = p.lambdaRegularize;
ap.maxIterations = p.maxIterationsOptimize;
ap.maxPlateauwidth = p.maxPlateauwidthOptimize;
ap.minNumInliers = p.minNumInliers;
ap.regularize = p.regularize;
ap.regularizerModelIndex = p.regularizerIndex;
ap.rejectIdentity = p.rejectIdentity;
/**
* Get all patches that will be affected.
*/
final List<Patch> allPatches = new ArrayList<Patch>();
for (final Layer l : layer.getParent().getLayers().subList(p.firstLayerIndex, p.lastLayerIndex + 1)) for (final Displayable d : l.getDisplayables(Patch.class)) allPatches.add((Patch) d);
/**
* Unset the coordinate transforms of all patches if desired.
*/
if (p.clearTransform) {
if (worker != null)
worker.setTaskName("Clearing present transforms");
setCoordinateTransform(allPatches, null, Runtime.getRuntime().availableProcessors());
Display.repaint();
}
if (worker != null)
worker.setTaskName("Establishing SIFT correspondences");
final List<AbstractAffineTile2D<?>> tiles = new ArrayList<AbstractAffineTile2D<?>>();
final List<AbstractAffineTile2D<?>> fixedTiles = new ArrayList<AbstractAffineTile2D<?>>();
final List<Patch> fixedPatches = new ArrayList<Patch>();
if (active != null && active instanceof Patch)
fixedPatches.add((Patch) active);
Align.tilesFromPatches(ap, patches, fixedPatches, tiles, fixedTiles);
final List<AbstractAffineTile2D<?>[]> tilePairs = new ArrayList<AbstractAffineTile2D<?>[]>();
if (p.tilesAreInPlace)
AbstractAffineTile2D.pairOverlappingTiles(tiles, tilePairs);
else
AbstractAffineTile2D.pairTiles(tiles, tilePairs);
AbstractAffineTile2D<?> fixedTile = null;
if (fixedTiles.size() > 0)
fixedTile = fixedTiles.get(0);
else
fixedTile = tiles.get(0);
Align.connectTilePairs(ap, tiles, tilePairs, p.maxNumThreadsSift, p.multipleHypotheses);
/**
* Shift all local coordinates into the original image frame
*/
for (final AbstractAffineTile2D<?> tile : tiles) {
final Rectangle box = tile.getPatch().getCoordinateTransformBoundingBox();
for (final PointMatch m : tile.getMatches()) {
final double[] l = m.getP1().getL();
final double[] w = m.getP1().getW();
l[0] += box.x;
l[1] += box.y;
w[0] = l[0];
w[1] = l[1];
}
}
if (Thread.currentThread().isInterrupted())
return;
final List<Set<Tile<?>>> graphs = AbstractAffineTile2D.identifyConnectedGraphs(tiles);
if (graphs.size() > 1)
Utils.log("Could not interconnect all images with correspondences. ");
final List<AbstractAffineTile2D<?>> interestingTiles;
/**
* Find largest graph.
*/
Set<Tile<?>> largestGraph = null;
for (final Set<Tile<?>> graph : graphs) if (largestGraph == null || largestGraph.size() < graph.size())
largestGraph = graph;
interestingTiles = new ArrayList<AbstractAffineTile2D<?>>();
for (final Tile<?> t : largestGraph) interestingTiles.add((AbstractAffineTile2D<?>) t);
if (Thread.currentThread().isInterrupted())
return;
Utils.log("Estimating lens model:");
/* initialize with pure affine */
Align.optimizeTileConfiguration(ap, interestingTiles, fixedTiles);
/* measure the current error */
double e = 0;
int n = 0;
for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) {
e += pm.getDistance();
++n;
}
e /= n;
double dEpsilon_i = 0;
double epsilon_i = e;
double dEpsilon_0 = 0;
NonLinearTransform lensModel = null;
Utils.log("0: epsilon = " + e);
/* Store original point locations */
final HashMap<Point, Point> originalPoints = new HashMap<Point, Point>();
for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) originalPoints.put(pm.getP1(), pm.getP1().clone());
/* ad hoc conditions to terminate iteration:
* small improvement ( 1/1000) relative to first iteration
* less than 20 iterations
* at least 2 iterations */
for (int i = 1; i < 20 && (i < 2 || dEpsilon_i <= dEpsilon_0 / 1000); ++i) {
if (Thread.currentThread().isInterrupted())
return;
/* Some data shuffling for the lens correction interface */
final List<PointMatchCollectionAndAffine> matches = new ArrayList<PointMatchCollectionAndAffine>();
for (final AbstractAffineTile2D<?>[] tilePair : tilePairs) {
final AffineTransform a = tilePair[0].createAffine();
a.preConcatenate(tilePair[1].getModel().createInverseAffine());
final Collection<PointMatch> commonMatches = new ArrayList<PointMatch>();
tilePair[0].commonPointMatches(tilePair[1], commonMatches);
final Collection<PointMatch> originalCommonMatches = new ArrayList<PointMatch>();
for (final PointMatch pm : commonMatches) originalCommonMatches.add(new PointMatch(originalPoints.get(pm.getP1()), originalPoints.get(pm.getP2())));
matches.add(new PointMatchCollectionAndAffine(a, originalCommonMatches));
}
if (worker != null)
worker.setTaskName("Estimating lens distortion correction");
lensModel = Distortion_Correction.createInverseDistortionModel(matches, p.dimension, p.lambda, (int) fixedTile.getWidth(), (int) fixedTile.getHeight());
/* update local points */
for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) {
final Point currentPoint = pm.getP1();
final Point originalPoint = originalPoints.get(currentPoint);
final double[] l = currentPoint.getL();
final double[] lo = originalPoint.getL();
l[0] = lo[0];
l[1] = lo[1];
lensModel.applyInPlace(l);
}
/* re-optimize */
Align.optimizeTileConfiguration(ap, interestingTiles, fixedTiles);
/* measure the current error */
e = 0;
n = 0;
for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) {
e += pm.getDistance();
++n;
}
e /= n;
dEpsilon_i = e - epsilon_i;
epsilon_i = e;
if (i == 1)
dEpsilon_0 = dEpsilon_i;
Utils.log(i + ": epsilon = " + e);
Utils.log(i + ": delta epsilon = " + dEpsilon_i);
}
if (lensModel != null) {
if (p.visualize) {
if (Thread.currentThread().isInterrupted())
return;
if (worker != null)
worker.setTaskName("Visualizing lens distortion correction");
lensModel.visualizeSmall(p.lambda);
}
if (worker != null)
worker.setTaskName("Applying lens distortion correction");
appendCoordinateTransform(allPatches, lensModel, Runtime.getRuntime().availableProcessors());
Utils.log("Done.");
} else
Utils.log("No lens model found.");
}
use of mpicbg.trakem2.align.AbstractAffineTile2D in project TrakEM2 by trakem2.
the class StitchingTEM method montageWithPhaseCorrelation.
/**
* Perform montage based on phase correlation
* @param col collection of patches
* @param param phase correlation parameters
*/
public static void montageWithPhaseCorrelation(final Collection<Patch> col, final PhaseCorrelationParam param) {
if (null == col || col.size() < 1)
return;
final ArrayList<Patch> al = new ArrayList<Patch>(col);
final ArrayList<AbstractAffineTile2D<?>> tiles = new ArrayList<AbstractAffineTile2D<?>>();
final ArrayList<AbstractAffineTile2D<?>> fixed_tiles = new ArrayList<AbstractAffineTile2D<?>>();
for (final Patch p : al) {
// Pre-check: just a warning
final int aff_type = p.getAffineTransform().getType();
switch(p.getAffineTransform().getType()) {
case AffineTransform.TYPE_IDENTITY:
case AffineTransform.TYPE_TRANSLATION:
// ok
break;
default:
Utils.log2("WARNING: patch with a non-translation transform: " + p);
break;
}
// create tiles
final TranslationTile2D tile = new TranslationTile2D(new TranslationModel2D(), p);
tiles.add(tile);
if (p.isLocked2()) {
Utils.log("Added fixed (locked) tile " + p);
fixed_tiles.add(tile);
}
}
// Get acceptable values
double cc_scale = param.cc_scale;
if (cc_scale < 0 || cc_scale > 1) {
Utils.log("Unacceptable cc_scale of " + param.cc_scale + ". Using 1 instead.");
cc_scale = 1;
}
float overlap = param.overlap;
if (overlap < 0 || overlap > 1) {
Utils.log("Unacceptable overlap of " + param.overlap + ". Using 1 instead.");
overlap = 1;
}
for (int i = 0; i < al.size(); i++) {
final Patch p1 = al.get(i);
final Rectangle r1 = p1.getBoundingBox();
// find overlapping, add as connections
for (int j = i + 1; j < al.size(); j++) {
if (Thread.currentThread().isInterrupted())
return;
final Patch p2 = al.get(j);
final Rectangle r2 = p2.getBoundingBox();
if (r1.intersects(r2)) {
// Skip if it's a diagonal overlap
final int dx = Math.abs(r1.x - r2.x);
final int dy = Math.abs(r1.y - r2.y);
if (dx > r1.width / 2 && dy > r1.height / 2) {
// skip diagonal match
Utils.log2("Skipping diagonal overlap between " + p1 + " and " + p2);
continue;
}
p1.getProject().getLoader().releaseToFit((long) (p1.getWidth() * p1.getHeight() * 25));
final double[] R;
if (1 == overlap) {
R = correlate(p1, p2, overlap, cc_scale, TOP_BOTTOM, 0, 0, param.min_R);
if (SUCCESS == R[2]) {
addMatches(tiles.get(i), tiles.get(j), R[0], R[1]);
}
} else {
switch(getClosestOverlapLocation(p1, p2)) {
case // p1 overlaps p2 from the left
0:
R = correlate(p1, p2, overlap, cc_scale, LEFT_RIGHT, 0, 0, param.min_R);
if (SUCCESS == R[2]) {
addMatches(tiles.get(i), tiles.get(j), R[0], R[1]);
}
break;
case // p1 overlaps p2 from the top
1:
R = correlate(p1, p2, overlap, cc_scale, TOP_BOTTOM, 0, 0, param.min_R);
if (SUCCESS == R[2]) {
addMatches(tiles.get(i), tiles.get(j), R[0], R[1]);
}
break;
case // p1 overlaps p2 from the right
2:
R = correlate(p2, p1, overlap, cc_scale, LEFT_RIGHT, 0, 0, param.min_R);
if (SUCCESS == R[2]) {
addMatches(tiles.get(j), tiles.get(i), R[0], R[1]);
}
break;
case // p1 overlaps p2 from the bottom
3:
R = correlate(p2, p1, overlap, cc_scale, TOP_BOTTOM, 0, 0, param.min_R);
if (SUCCESS == R[2]) {
addMatches(tiles.get(j), tiles.get(i), R[0], R[1]);
}
break;
default:
Utils.log("Unknown overlap direction!");
continue;
}
}
}
}
}
if (param.remove_disconnected || param.hide_disconnected) {
for (final Iterator<AbstractAffineTile2D<?>> it = tiles.iterator(); it.hasNext(); ) {
final AbstractAffineTile2D<?> t = it.next();
if (null != t.getMatches() && t.getMatches().isEmpty()) {
if (param.hide_disconnected)
t.getPatch().setVisible(false);
else if (param.remove_disconnected)
t.getPatch().remove(false);
it.remove();
}
}
}
// Optimize tile configuration by removing bad matches
optimizeTileConfiguration(tiles, fixed_tiles, param);
for (final AbstractAffineTile2D<?> t : tiles) t.getPatch().setAffineTransform(t.getModel().createAffine());
try {
Display.repaint(al.get(0).getLayer());
} catch (final Exception e) {
}
}
use of mpicbg.trakem2.align.AbstractAffineTile2D in project TrakEM2 by trakem2.
the class AlignTask method alignMultiLayerMosaicTask.
@SuppressWarnings({ "unchecked", "rawtypes" })
public static final void alignMultiLayerMosaicTask(final List<Layer> layerRange, final Patch nail, final Align.Param cp, final Align.ParamOptimize p, final Align.ParamOptimize pcp, final boolean tilesAreInPlaceIn, final boolean largestGraphOnlyIn, final boolean hideDisconnectedTilesIn, final boolean deleteDisconnectedTilesIn, final boolean deformIn) {
/* register */
final List<AbstractAffineTile2D<?>> allTiles = new ArrayList<AbstractAffineTile2D<?>>();
final List<AbstractAffineTile2D<?>> allFixedTiles = new ArrayList<AbstractAffineTile2D<?>>();
final List<AbstractAffineTile2D<?>> previousLayerTiles = new ArrayList<AbstractAffineTile2D<?>>();
final HashMap<Patch, PointMatch> tileCenterPoints = new HashMap<Patch, PointMatch>();
final Collection<Patch> fixedPatches = new HashSet<Patch>();
if (null != nail)
fixedPatches.add(nail);
Layer previousLayer = null;
for (final Layer layer : layerRange) {
/* align all tiles in the layer */
final List<Patch> patches = new ArrayList<Patch>();
for (// ignore hidden tiles
final Displayable a : // ignore hidden tiles
layer.getDisplayables(Patch.class, true)) if (a instanceof Patch)
patches.add((Patch) a);
final List<AbstractAffineTile2D<?>> currentLayerTiles = new ArrayList<AbstractAffineTile2D<?>>();
final List<AbstractAffineTile2D<?>> fixedTiles = new ArrayList<AbstractAffineTile2D<?>>();
Align.tilesFromPatches(p, patches, fixedPatches, currentLayerTiles, fixedTiles);
// Will consider graphs and hide/delete tiles when all cross-layer graphs are found.
alignTiles(p, currentLayerTiles, fixedTiles, tilesAreInPlaceIn, false, false, false);
if (Thread.currentThread().isInterrupted())
return;
/* connect to the previous layer */
/* generate tiles with the cross-section model from the current layer tiles */
/* ------------------------------------------------------------------------ */
/* TODO step back and make tiles bare containers for a patch and a model such that by changing the model the tile can be reused */
final HashMap<Patch, AbstractAffineTile2D<?>> currentLayerPatchTiles = new HashMap<Patch, AbstractAffineTile2D<?>>();
for (final AbstractAffineTile2D<?> t : currentLayerTiles) currentLayerPatchTiles.put(t.getPatch(), t);
final List<AbstractAffineTile2D<?>> csCurrentLayerTiles = new ArrayList<AbstractAffineTile2D<?>>();
final Set<AbstractAffineTile2D<?>> csFixedTiles = new HashSet<AbstractAffineTile2D<?>>();
Align.tilesFromPatches(cp, patches, fixedPatches, csCurrentLayerTiles, csFixedTiles);
final HashMap<Tile<?>, AbstractAffineTile2D<?>> tileTiles = new HashMap<Tile<?>, AbstractAffineTile2D<?>>();
for (final AbstractAffineTile2D<?> t : csCurrentLayerTiles) tileTiles.put(currentLayerPatchTiles.get(t.getPatch()), t);
for (final AbstractAffineTile2D<?> t : currentLayerTiles) {
final AbstractAffineTile2D<?> csLayerTile = tileTiles.get(t);
csLayerTile.addMatches(t.getMatches());
for (final Tile<?> ct : t.getConnectedTiles()) csLayerTile.addConnectedTile(tileTiles.get(ct));
}
/* add a fixed tile only if there was a Patch selected */
allFixedTiles.addAll(csFixedTiles);
/* first, align connected graphs to each other */
/* graphs in the current layer */
final List<Set<Tile<?>>> currentLayerGraphs = AbstractAffineTile2D.identifyConnectedGraphs(csCurrentLayerTiles);
if (Thread.currentThread().isInterrupted())
return;
// /* TODO just for visualization */
// for ( final Set< Tile< ? > > graph : currentLayerGraphs )
// {
// Display.getFront().getSelection().clear();
// Display.getFront().setLayer( ( ( AbstractAffineTile2D< ? > )graph.iterator().next() ).getPatch().getLayer() );
//
// for ( final Tile< ? > tile : graph )
// {
// Display.getFront().getSelection().add( ( ( AbstractAffineTile2D< ? > )tile ).getPatch() );
// Display.repaint();
// }
// Utils.showMessage( "OK" );
// }
/* graphs from the whole system that are present in the previous layer */
final List<Set<Tile<?>>> graphs = AbstractAffineTile2D.identifyConnectedGraphs(allTiles);
final HashMap<Set<Tile<?>>, Set<Tile<?>>> graphGraphs = new HashMap<Set<Tile<?>>, Set<Tile<?>>>();
for (final Set<Tile<?>> graph : graphs) {
if (Thread.currentThread().isInterrupted())
return;
final Set<Tile<?>> previousLayerGraph = new HashSet<Tile<?>>();
for (final Tile<?> tile : previousLayerTiles) {
if (graph.contains(tile)) {
graphGraphs.put(graph, previousLayerGraph);
previousLayerGraph.add(tile);
}
}
}
final Collection<Set<Tile<?>>> previousLayerGraphs = graphGraphs.values();
// /* TODO just for visualization */
// for ( final Set< Tile< ? > > graph : previousLayerGraphs )
// {
// Display.getFront().getSelection().clear();
// Display.getFront().setLayer( ( ( AbstractAffineTile2D< ? > )graph.iterator().next() ).getPatch().getLayer() );
//
// for ( final Tile< ? > tile : graph )
// {
// Display.getFront().getSelection().add( ( ( AbstractAffineTile2D< ? > )tile ).getPatch() );
// Display.repaint();
// }
// Utils.showMessage( "OK" );
// }
/* generate snapshots of the graphs and preregister them using the parameters defined in cp */
final List<AbstractAffineTile2D<?>[]> crossLayerTilePairs = new ArrayList<AbstractAffineTile2D<?>[]>();
for (final Set<Tile<?>> currentLayerGraph : currentLayerGraphs) {
for (final Set<Tile<?>> previousLayerGraph : previousLayerGraphs) {
if (Thread.currentThread().isInterrupted())
return;
alignGraphs(cp, layer, previousLayer, currentLayerGraph, previousLayerGraph);
/* TODO this is pointless data shuffling just for type incompatibility---fix this at the root */
final ArrayList<AbstractAffineTile2D<?>> previousLayerGraphTiles = new ArrayList<AbstractAffineTile2D<?>>();
previousLayerGraphTiles.addAll((Set) previousLayerGraph);
final ArrayList<AbstractAffineTile2D<?>> currentLayerGraphTiles = new ArrayList<AbstractAffineTile2D<?>>();
currentLayerGraphTiles.addAll((Set) currentLayerGraph);
AbstractAffineTile2D.pairOverlappingTiles(previousLayerGraphTiles, currentLayerGraphTiles, crossLayerTilePairs);
}
}
/* ------------------------------------------------------------------------ */
/* this is without the affine/rigid approximation per graph */
// AbstractAffineTile2D.pairTiles( previousLayerTiles, csCurrentLayerTiles, crossLayerTilePairs );
Align.connectTilePairs(cp, csCurrentLayerTiles, crossLayerTilePairs, Runtime.getRuntime().availableProcessors());
if (Thread.currentThread().isInterrupted())
return;
// for ( final AbstractAffineTile2D< ? >[] tilePair : crossLayerTilePairs )
// {
// Display.getFront().setLayer( tilePair[ 0 ].getPatch().getLayer() );
// Display.getFront().getSelection().clear();
// Display.getFront().getSelection().add( tilePair[ 0 ].getPatch() );
// Display.getFront().getSelection().add( tilePair[ 1 ].getPatch() );
//
// Utils.showMessage( "1: OK?" );
//
// Display.getFront().setLayer( tilePair[ 1 ].getPatch().getLayer() );
// Display.getFront().getSelection().clear();
// Display.getFront().getSelection().add( tilePair[ 0 ].getPatch() );
// Display.getFront().getSelection().add( tilePair[ 1 ].getPatch() );
//
// Utils.showMessage( "2: OK?" );
// }
/* prepare the next loop */
allTiles.addAll(csCurrentLayerTiles);
previousLayerTiles.clear();
previousLayerTiles.addAll(csCurrentLayerTiles);
/* optimize */
Align.optimizeTileConfiguration(pcp, allTiles, allFixedTiles);
if (Thread.currentThread().isInterrupted())
return;
for (final AbstractAffineTile2D<?> t : allTiles) t.getPatch().setAffineTransform(t.getModel().createAffine());
previousLayer = layer;
}
final List<Set<Tile<?>>> graphs = AbstractAffineTile2D.identifyConnectedGraphs(allTiles);
final List<AbstractAffineTile2D<?>> interestingTiles = new ArrayList<AbstractAffineTile2D<?>>();
if (largestGraphOnlyIn && (hideDisconnectedTilesIn || deleteDisconnectedTilesIn)) {
if (Thread.currentThread().isInterrupted())
return;
/* find largest graph. */
Set<Tile<?>> largestGraph = null;
for (final Set<Tile<?>> graph : graphs) if (largestGraph == null || largestGraph.size() < graph.size())
largestGraph = graph;
final Set<AbstractAffineTile2D<?>> tiles_to_keep = new HashSet<AbstractAffineTile2D<?>>();
for (final Tile<?> t : largestGraph) tiles_to_keep.add((AbstractAffineTile2D<?>) t);
if (hideDisconnectedTilesIn)
for (final AbstractAffineTile2D<?> t : allTiles) if (!tiles_to_keep.contains(t))
t.getPatch().setVisible(false);
if (deleteDisconnectedTilesIn)
for (final AbstractAffineTile2D<?> t : allTiles) if (!tiles_to_keep.contains(t))
t.getPatch().remove(false);
interestingTiles.addAll(tiles_to_keep);
} else
interestingTiles.addAll(allTiles);
if (deformIn) {
/* ############################################ */
/* experimental: use the center points of all tiles to define a MLS deformation from the pure intra-layer registration to the globally optimal */
Utils.log("deforming...");
/* store the center location of each single tile for later deformation */
for (final AbstractAffineTile2D<?> t : interestingTiles) {
final double[] c = new double[] { t.getWidth() / 2.0, t.getHeight() / 2.0 };
t.getModel().applyInPlace(c);
final Point q = new Point(c);
tileCenterPoints.put(t.getPatch(), new PointMatch(q.clone(), q));
}
for (final Layer layer : layerRange) {
Utils.log("layer" + layer);
if (Thread.currentThread().isInterrupted())
return;
/* again, align all tiles in the layer */
final List<Patch> patches = new ArrayList<Patch>();
for (final Displayable a : layer.getDisplayables(Patch.class)) if (a instanceof Patch)
patches.add((Patch) a);
final List<AbstractAffineTile2D<?>> currentLayerTiles = new ArrayList<AbstractAffineTile2D<?>>();
final List<AbstractAffineTile2D<?>> fixedTiles = new ArrayList<AbstractAffineTile2D<?>>();
Align.tilesFromPatches(p, patches, fixedPatches, currentLayerTiles, fixedTiles);
/* add a fixed tile only if there was a Patch selected */
allFixedTiles.addAll(fixedTiles);
// will consider graphs and hide/delete tiles when all cross-layer graphs are found
alignTiles(p, currentLayerTiles, fixedTiles, true, false, false, false);
/* for each independent graph do an independent transform */
final List<Set<Tile<?>>> currentLayerGraphs = AbstractAffineTile2D.identifyConnectedGraphs(currentLayerTiles);
for (final Set<Tile<?>> graph : currentLayerGraphs) {
/* update the tile-center pointmatches */
final Collection<PointMatch> matches = new ArrayList<PointMatch>();
final Collection<AbstractAffineTile2D<?>> toBeDeformedTiles = new ArrayList<AbstractAffineTile2D<?>>();
for (final AbstractAffineTile2D<?> t : (Collection<AbstractAffineTile2D<?>>) (Collection) graph) {
final PointMatch pm = tileCenterPoints.get(t.getPatch());
if (pm == null)
continue;
final double[] pl = pm.getP1().getL();
pl[0] = t.getWidth() / 2.0;
pl[1] = t.getHeight() / 2.0;
t.getModel().applyInPlace(pl);
matches.add(pm);
toBeDeformedTiles.add(t);
}
for (final AbstractAffineTile2D<?> t : toBeDeformedTiles) {
if (Thread.currentThread().isInterrupted())
return;
try {
final Patch patch = t.getPatch();
final Rectangle pbox = patch.getCoordinateTransformBoundingBox();
final AffineTransform pat = new AffineTransform();
pat.translate(-pbox.x, -pbox.y);
pat.preConcatenate(patch.getAffineTransform());
final mpicbg.trakem2.transform.AffineModel2D toWorld = new mpicbg.trakem2.transform.AffineModel2D();
toWorld.set(pat);
final MovingLeastSquaresTransform2 mlst = Align.createMLST(matches, 1.0f);
final CoordinateTransformList<CoordinateTransform> ctl = new CoordinateTransformList<CoordinateTransform>();
ctl.add(toWorld);
ctl.add(mlst);
ctl.add(toWorld.createInverse());
patch.appendCoordinateTransform(ctl);
patch.getProject().getLoader().regenerateMipMaps(patch);
} catch (final Exception e) {
e.printStackTrace();
}
}
}
}
}
layerRange.get(0).getParent().setMinimumDimensions();
IJ.log("Done: register multi-layer mosaic.");
return;
}
use of mpicbg.trakem2.align.AbstractAffineTile2D in project TrakEM2 by trakem2.
the class Align method alignTileCollections.
/**
* Align two collections of tiles
* @param p
* @param a
* @param b
*/
public static final void alignTileCollections(final Param p, final Collection<AbstractAffineTile2D<?>> a, final Collection<AbstractAffineTile2D<?>> b) {
final ArrayList<Patch> pa = new ArrayList<Patch>();
final ArrayList<Patch> pb = new ArrayList<Patch>();
for (final AbstractAffineTile2D<?> t : a) pa.add(t.getPatch());
for (final AbstractAffineTile2D<?> t : b) pb.add(t.getPatch());
final Layer la = pa.iterator().next().getLayer();
final Layer lb = pb.iterator().next().getLayer();
final Rectangle boxA = Displayable.getBoundingBox(pa, null);
final Rectangle boxB = Displayable.getBoundingBox(pb, null);
final double scale = Math.min(1.0, Math.min(Math.min((double) p.sift.maxOctaveSize / boxA.width, (double) p.sift.maxOctaveSize / boxA.height), Math.min((double) p.sift.maxOctaveSize / boxB.width, (double) p.sift.maxOctaveSize / boxB.height)));
final Param pp = p.clone();
pp.maxEpsilon *= scale;
final FloatArray2DSIFT sift = new FloatArray2DSIFT(pp.sift);
final SIFT ijSIFT = new SIFT(sift);
final Collection<Feature> featuresA = new ArrayList<Feature>();
final Collection<Feature> featuresB = new ArrayList<Feature>();
final List<PointMatch> candidates = new ArrayList<PointMatch>();
final List<PointMatch> inliers = new ArrayList<PointMatch>();
long s = System.currentTimeMillis();
ijSIFT.extractFeatures(la.getProject().getLoader().getFlatImage(la, boxA, scale, 0xffffffff, ImagePlus.GRAY8, null, pa, true, Color.GRAY).getProcessor(), featuresA);
Utils.log(featuresA.size() + " features extracted in graph A in layer \"" + la.getTitle() + "\" (took " + (System.currentTimeMillis() - s) + " ms).");
s = System.currentTimeMillis();
ijSIFT.extractFeatures(lb.getProject().getLoader().getFlatImage(lb, boxB, scale, 0xffffffff, ImagePlus.GRAY8, null, pb, true, Color.GRAY).getProcessor(), featuresB);
Utils.log(featuresB.size() + " features extracted in graph B in layer \"" + lb.getTitle() + "\" (took " + (System.currentTimeMillis() - s) + " ms).");
if (featuresA.size() > 0 && featuresB.size() > 0) {
s = System.currentTimeMillis();
FeatureTransform.matchFeatures(featuresA, featuresB, candidates, pp.rod);
final AbstractAffineModel2D<?> model;
switch(p.expectedModelIndex) {
case 0:
model = new TranslationModel2D();
break;
case 1:
model = new RigidModel2D();
break;
case 2:
model = new SimilarityModel2D();
break;
case 3:
model = new AffineModel2D();
break;
default:
return;
}
boolean modelFound;
boolean again = false;
try {
do {
again = false;
modelFound = model.filterRansac(candidates, inliers, 1000, p.maxEpsilon, p.minInlierRatio, p.minNumInliers, 3);
if (modelFound && p.rejectIdentity) {
final ArrayList<Point> points = new ArrayList<Point>();
PointMatch.sourcePoints(inliers, points);
if (Transforms.isIdentity(model, points, p.identityTolerance)) {
Utils.log("Identity transform for " + inliers.size() + " matches rejected.");
candidates.removeAll(inliers);
inliers.clear();
again = true;
}
}
} while (again);
} catch (final NotEnoughDataPointsException e) {
modelFound = false;
}
if (modelFound) {
Utils.log("Model found for graph A and B in layers \"" + la.getTitle() + "\" and \"" + lb.getTitle() + "\":\n correspondences " + inliers.size() + " of " + candidates.size() + "\n average residual error " + (model.getCost() / scale) + " px\n took " + (System.currentTimeMillis() - s) + " ms");
final AffineTransform at = new AffineTransform();
at.translate(boxA.x, boxA.y);
at.scale(1.0f / scale, 1.0f / scale);
at.concatenate(model.createAffine());
at.scale(scale, scale);
at.translate(-boxB.x, -boxB.y);
for (final Patch t : pa) t.preTransform(at, false);
Display.repaint(la);
} else
Utils.log("No model found for graph A and B in layers \"" + la.getTitle() + "\" and \"" + lb.getTitle() + "\":\n correspondence candidates " + candidates.size() + "\n took " + (System.currentTimeMillis() - s) + " ms");
}
}
Aggregations