use of mpicbg.trakem2.transform.CoordinateTransformList in project TrakEM2 by trakem2.
the class Patch method keyPressed.
@Override
public void keyPressed(final KeyEvent ke) {
final Object source = ke.getSource();
if (!(source instanceof DisplayCanvas))
return;
final DisplayCanvas dc = (DisplayCanvas) source;
final Roi roi = dc.getFakeImagePlus().getRoi();
final int mod = ke.getModifiers();
switch(ke.getKeyCode()) {
case KeyEvent.VK_C:
// Ignoring masks: outside is already black, and ImageJ cannot handle alpha masks.
if (0 == (mod ^ (Event.SHIFT_MASK | Event.ALT_MASK))) {
// Place the source image, untransformed, into clipboard:
final ImagePlus imp = getImagePlus();
if (null != imp)
imp.copy(false);
} else if (0 == mod || (0 == (mod ^ Event.SHIFT_MASK))) {
CoordinateTransformList<CoordinateTransform> list = null;
if (hasCoordinateTransform()) {
list = new CoordinateTransformList<CoordinateTransform>();
list.add(getCoordinateTransform());
}
if (0 == mod) {
// SHIFT is not down
final AffineModel2D am = new AffineModel2D();
am.set(this.at);
if (null == list)
list = new CoordinateTransformList<CoordinateTransform>();
list.add(am);
}
ImageProcessor ip;
if (null != list) {
final TransformMesh mesh = new TransformMesh(list, meshResolution, o_width, o_height);
final TransformMeshMapping mapping = new TransformMeshMapping(mesh);
ip = mapping.createMappedImageInterpolated(getImageProcessor());
} else {
ip = getImageProcessor();
}
new ImagePlus(this.title, ip).copy(false);
}
ke.consume();
break;
case KeyEvent.VK_F:
// fill mask with current ROI using
if (null != roi && M.isAreaROI(roi)) {
Bureaucrat.createAndStart(new Worker.Task("Filling image mask") {
@Override
public void exec() {
getLayerSet().addDataEditStep(Patch.this);
if (0 == mod) {
addAlphaMask(roi, ProjectToolbar.getForegroundColorValue());
} else if (0 == (mod ^ Event.SHIFT_MASK)) {
// shift is down: fill outside
try {
final Area localRoi = M.areaInInts(M.getArea(roi)).createTransformedArea(at.createInverse());
final Area invLocalRoi = new Area(new Rectangle(0, 0, getOWidth(), getOHeight()));
invLocalRoi.subtract(localRoi);
addAlphaMaskLocal(invLocalRoi, ProjectToolbar.getForegroundColorValue());
} catch (final NoninvertibleTransformException e) {
IJError.print(e);
return;
}
}
getLayerSet().addDataEditStep(Patch.this);
// wait
try {
updateMipMaps().get();
} catch (final Throwable t) {
IJError.print(t);
}
Display.repaint();
}
}, project);
}
// capturing:
ke.consume();
break;
default:
super.keyPressed(ke);
break;
}
}
use of mpicbg.trakem2.transform.CoordinateTransformList in project TrakEM2 by trakem2.
the class Patch method getArea.
/**
* Returns an Area in world coords representing the inside of this Patch. The fully alpha pixels are considered outside.
*/
@Override
public Area getArea() {
CoordinateTransform ct = null;
if (hasAlphaMask()) {
// Read the mask as a ROI for the 0 pixels only and apply the AffineTransform to it:
ImageProcessor alpha_mask = getAlphaMask();
if (null == alpha_mask) {
Utils.log2("Could not retrieve alpha mask for " + this);
} else {
if (hasCoordinateTransform()) {
// must transform it
ct = getCoordinateTransform();
final TransformMesh mesh = new TransformMesh(ct, meshResolution, o_width, o_height);
final TransformMeshMapping mapping = new TransformMeshMapping(mesh);
// Without interpolation
alpha_mask = mapping.createMappedImage(alpha_mask);
// Keep in mind the affine of the Patch already contains the translation specified by the mesh bounds.
}
// Threshold all non-zero areas of the mask:
alpha_mask.setThreshold(1, 255, ImageProcessor.NO_LUT_UPDATE);
final ImagePlus imp = new ImagePlus("", alpha_mask);
// TODO replace by our much faster method that scans by line, in AmiraImporter
final ThresholdToSelection tts = new ThresholdToSelection();
tts.setup("", imp);
tts.run(alpha_mask);
final Roi roi = imp.getRoi();
if (null == roi) {
// All pixels in the alpha mask have a value of zero
return new Area();
}
return M.getArea(roi).createTransformedArea(this.at);
}
}
// No alpha mask, or error in retrieving it:
final int[] x = new int[o_width + o_width + o_height + o_height];
final int[] y = new int[x.length];
int next = 0;
// Top edge:
for (int i = 0; i <= o_width; i++, next++) {
// len: o_width + 1
x[next] = i;
y[next] = 0;
}
// Right edge:
for (int i = 1; i <= o_height; i++, next++) {
// len: o_height
x[next] = o_width;
y[next] = i;
}
// bottom edge:
for (int i = o_width - 1; i > -1; i--, next++) {
// len: o_width
x[next] = i;
y[next] = o_height;
}
// left edge:
for (int i = o_height - 1; i > 0; i--, next++) {
// len: o_height -1
x[next] = 0;
y[next] = i;
}
if (hasCoordinateTransform() && null == ct)
ct = getCoordinateTransform();
if (null != ct) {
final CoordinateTransformList<CoordinateTransform> t = new CoordinateTransformList<CoordinateTransform>();
t.add(ct);
final TransformMesh mesh = new TransformMesh(ct, meshResolution, o_width, o_height);
final Rectangle box = mesh.getBoundingBox();
final AffineTransform aff = new AffineTransform(this.at);
// Must correct for the inverse of the mesh translation, because the affine also includes the translation.
aff.translate(-box.x, -box.y);
final AffineModel2D affm = new AffineModel2D();
affm.set(aff);
t.add(affm);
/*
* WORKS FINE, but for points that fall outside the mesh, they don't get transformed!
// Do it like Patch does it to generate the mipmap, with a mesh (and all the imprecisions of a mesh):
final CoordinateTransformList t = new CoordinateTransformList();
final TransformMesh mesh = new TransformMesh(this.ct, meshResolution, o_width, o_height);
final AffineTransform aff = new AffineTransform(this.at);
t.add(mesh);
final AffineModel2D affm = new AffineModel2D();
affm.set(aff);
t.add(affm);
*/
final double[] f = new double[] { x[0], y[0] };
t.applyInPlace(f);
final Path2D.Float path = new Path2D.Float(Path2D.Float.WIND_EVEN_ODD, x.length + 1);
path.moveTo(f[0], f[1]);
for (int i = 1; i < x.length; i++) {
f[0] = x[i];
f[1] = y[i];
t.applyInPlace(f);
path.lineTo(f[0], f[1]);
}
// line to last call to moveTo
path.closePath();
return new Area(path);
} else {
return new Area(new Polygon(x, y, x.length)).createTransformedArea(this.at);
}
}
use of mpicbg.trakem2.transform.CoordinateTransformList in project TrakEM2 by trakem2.
the class Patch method getFullCoordinateTransform.
/**
* Create a {@link CoordinateTransform} that incorporates both the
* {@link CoordinateTransform} of this {@link Patch} (if present) and its
* {@link AffineTransform}. The returned {@link CoordinateTransform} directly
* transfers the {@link Patch} into world coordinates. An image can be rendered
* e.g. using {@link mpicbg.ij.TransformMeshMapping} with an
* {@link mpicbg.models.TransformMesh}. Note that you may prefer to use
* {@link mpicbg.models.TransformMesh} which does not perform auto-boxing as
* opposed to {@link TransformMesh} in the mpicbg.trakem2 package.
*
* @return
*/
public final CoordinateTransform getFullCoordinateTransform() {
final CoordinateTransform ctp = getCoordinateTransform();
if (ctp == null) {
final AffineModel2D affine = new AffineModel2D();
affine.set(at);
return affine;
} else {
final Rectangle box = getCoordinateTransformBoundingBox();
final AffineTransform at2 = new AffineTransform(at);
at2.translate(-box.x, -box.y);
final AffineModel2D affine = new AffineModel2D();
affine.set(at2);
final CoordinateTransformList<CoordinateTransform> ctl = new CoordinateTransformList<CoordinateTransform>();
ctl.add(ctp);
ctl.add(affine);
return ctl;
}
}
use of mpicbg.trakem2.transform.CoordinateTransformList in project TrakEM2 by trakem2.
the class TMLHandler method makeCoordinateTransform.
private final void makeCoordinateTransform(String type, final HashMap<String, String> ht_attributes) {
try {
type = type.toLowerCase();
if (type.equals("ict_transform")) {
final CoordinateTransform ct = (CoordinateTransform) Class.forName(ht_attributes.get("class")).newInstance();
ct.init(ht_attributes.get("data"));
if (ct_list_stack.isEmpty()) {
if (last_patch != null)
last_ct = ct;
} else {
ct_list_stack.get(ct_list_stack.size() - 1).add(ct);
}
} else if (type.equals("iict_transform")) {
final InvertibleCoordinateTransform ict = (InvertibleCoordinateTransform) Class.forName(ht_attributes.get("class")).newInstance();
ict.init(ht_attributes.get("data"));
if (ct_list_stack.isEmpty()) {
if (last_patch != null)
last_ct = ict;
else if (last_stack != null)
last_ict = ict;
} else {
ct_list_stack.get(ct_list_stack.size() - 1).add(ict);
}
} else if (type.equals("ict_transform_list")) {
final CoordinateTransformList<CoordinateTransform> ctl = new CoordinateTransformList<CoordinateTransform>();
if (ct_list_stack.isEmpty()) {
if (last_patch != null)
last_ct = ctl;
} else
ct_list_stack.get(ct_list_stack.size() - 1).add(ctl);
ct_list_stack.add((TransformList) ctl);
} else if (type.equals("iict_transform_list")) {
final InvertibleCoordinateTransformList<InvertibleCoordinateTransform> ictl = new InvertibleCoordinateTransformList<InvertibleCoordinateTransform>();
if (ct_list_stack.isEmpty()) {
if (last_patch != null)
last_ct = ictl;
else if (last_stack != null)
last_ict = ictl;
} else
ct_list_stack.get(ct_list_stack.size() - 1).add(ictl);
ct_list_stack.add((TransformList) ictl);
}
} catch (Exception e) {
IJError.print(e);
}
}
use of mpicbg.trakem2.transform.CoordinateTransformList 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;
}
Aggregations