use of mpicbg.models.Tile in project TrakEM2 by trakem2.
the class StitchingTEM method stitchTopLeft.
/**
* Stitch array of patches with upper left rule
*
* @param patch
* @param grid_width
* @param default_bottom_top_overlap
* @param default_left_right_overlap
* @param optimize
* @return
*/
private static Runnable stitchTopLeft(final Patch[] patch, final int grid_width, final double default_bottom_top_overlap, final double default_left_right_overlap, final boolean optimize, final PhaseCorrelationParam param) {
return new Runnable() {
@Override
public void run() {
try {
final int LEFT = 0, TOP = 1;
int prev_i = 0;
int prev = LEFT;
double[] R1 = null, R2 = null;
// for minimization:
final ArrayList<AbstractAffineTile2D<?>> al_tiles = new ArrayList<AbstractAffineTile2D<?>>();
// first patch-tile:
final TranslationModel2D first_tile_model = new TranslationModel2D();
// first_tile_model.getAffine().setTransform( patch[ 0 ].getAffineTransform() );
first_tile_model.set((float) patch[0].getAffineTransform().getTranslateX(), (float) patch[0].getAffineTransform().getTranslateY());
al_tiles.add(new TranslationTile2D(first_tile_model, patch[0]));
for (int i = 1; i < patch.length; i++) {
if (Thread.currentThread().isInterrupted()) {
return;
}
// boundary checks: don't allow displacements beyond these values
final double default_dx = default_left_right_overlap;
final double default_dy = default_bottom_top_overlap;
// for minimization:
AbstractAffineTile2D<?> tile_left = null;
AbstractAffineTile2D<?> tile_top = null;
final TranslationModel2D tile_model = new TranslationModel2D();
// tile_model.getAffine().setTransform( patch[ i ].getAffineTransform() );
tile_model.set((float) patch[i].getAffineTransform().getTranslateX(), (float) patch[i].getAffineTransform().getTranslateY());
final AbstractAffineTile2D<?> tile = new TranslationTile2D(tile_model, patch[i]);
al_tiles.add(tile);
// stitch with the one above if starting row
if (0 == i % grid_width) {
prev_i = i - grid_width;
prev = TOP;
} else {
prev_i = i - 1;
prev = LEFT;
}
if (TOP == prev) {
// compare with top only
R1 = correlate(patch[prev_i], patch[i], param.overlap, param.cc_scale, TOP_BOTTOM, default_dx, default_dy, param.min_R);
R2 = null;
tile_top = al_tiles.get(i - grid_width);
} else {
// the one on the left
R2 = correlate(patch[prev_i], patch[i], param.overlap, param.cc_scale, LEFT_RIGHT, default_dx, default_dy, param.min_R);
tile_left = al_tiles.get(i - 1);
// the one above
if (i - grid_width > -1) {
R1 = correlate(patch[i - grid_width], patch[i], param.overlap, param.cc_scale, TOP_BOTTOM, default_dx, default_dy, param.min_R);
tile_top = al_tiles.get(i - grid_width);
} else {
R1 = null;
}
}
// boundary limits: don't move by more than the small dimension of the stripe
// TODO: only the dx for left (and the dy for top) should be compared and found to be smaller or equal; the other dimension should be unbounded -for example, for manually acquired, grossly out-of-grid tiles.
final int max_abs_delta;
final Rectangle box = new Rectangle();
final Rectangle box2 = new Rectangle();
// check and apply: falls back to default overlaps when getting bad results
if (TOP == prev) {
if (SUCCESS == R1[2]) {
// trust top
if (optimize)
addMatches(tile_top, tile, R1[0], R1[1]);
else {
patch[i - grid_width].getBoundingBox(box);
patch[i].setLocation(box.x + R1[0], box.y + R1[1]);
}
} else {
final Rectangle b2 = patch[i - grid_width].getBoundingBox(null);
// don't move: use default overlap
if (optimize)
addMatches(tile_top, tile, 0, b2.height - default_bottom_top_overlap);
else {
patch[i - grid_width].getBoundingBox(box);
patch[i].setLocation(box.x, box.y + b2.height - default_bottom_top_overlap);
}
}
} else {
// the one on top, if any
if (i - grid_width > -1) {
if (SUCCESS == R1[2]) {
// top is good
if (SUCCESS == R2[2]) {
// combine left and top
if (optimize) {
addMatches(tile_left, tile, R2[0], R2[1]);
addMatches(tile_top, tile, R1[0], R1[1]);
} else {
patch[i - 1].getBoundingBox(box);
patch[i - grid_width].getBoundingBox(box2);
patch[i].setLocation((box.x + R1[0] + box2.x + R2[0]) / 2, (box.y + R1[1] + box2.y + R2[1]) / 2);
}
} else {
// use top alone
if (optimize)
addMatches(tile_top, tile, R1[0], R1[1]);
else {
patch[i - grid_width].getBoundingBox(box);
patch[i].setLocation(box.x + R1[0], box.y + R1[1]);
}
}
} else {
// ignore top
if (SUCCESS == R2[2]) {
// use left alone
if (optimize)
addMatches(tile_left, tile, R2[0], R2[1]);
else {
patch[i - 1].getBoundingBox(box);
patch[i].setLocation(box.x + R2[0], box.y + R2[1]);
}
} else {
patch[prev_i].getBoundingBox(box);
patch[i - grid_width].getBoundingBox(box2);
// left not trusted, top not trusted: use a combination of defaults for both
if (optimize) {
addMatches(tile_left, tile, box.width - default_left_right_overlap, 0);
addMatches(tile_top, tile, 0, box2.height - default_bottom_top_overlap);
} else {
patch[i].setLocation(box.x + box.width - default_left_right_overlap, box2.y + box2.height - default_bottom_top_overlap);
}
}
}
} else if (SUCCESS == R2[2]) {
// use left alone (top not applicable in top row)
if (optimize)
addMatches(tile_left, tile, R2[0], R2[1]);
else {
patch[i - 1].getBoundingBox(box);
patch[i].setLocation(box.x + R2[0], box.y + R2[1]);
}
} else {
patch[prev_i].getBoundingBox(box);
// left not trusted, and top not applicable: use default overlap with left tile
if (optimize)
addMatches(tile_left, tile, box.width - default_left_right_overlap, 0);
else {
patch[i].setLocation(box.x + box.width - default_left_right_overlap, box.y);
}
}
}
if (!optimize)
Display.repaint(patch[i].getLayer(), patch[i], null, 0, false);
Utils.log2(i + ": Done patch " + patch[i]);
}
if (optimize) {
final ArrayList<AbstractAffineTile2D<?>> al_fixed_tiles = new ArrayList<AbstractAffineTile2D<?>>();
// Add locked tiles as fixed tiles, if any:
for (int i = 0; i < patch.length; i++) {
if (patch[i].isLocked2())
al_fixed_tiles.add(al_tiles.get(i));
}
if (al_fixed_tiles.isEmpty()) {
// When none, add the first one as fixed
al_fixed_tiles.add(al_tiles.get(0));
}
// Optimize iteratively tile configuration by removing bad matches
optimizeTileConfiguration(al_tiles, al_fixed_tiles, param);
for (final AbstractAffineTile2D<?> t : al_tiles) t.getPatch().setAffineTransform(t.getModel().createAffine());
}
// Remove or hide disconnected tiles
if (param.hide_disconnected || param.remove_disconnected) {
final List<Set<Tile<?>>> graphs = AbstractAffineTile2D.identifyConnectedGraphs(al_tiles);
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;
Utils.log("Size of largest stitching graph = " + largestGraph.size());
interestingTiles = new ArrayList<AbstractAffineTile2D<?>>();
for (final Tile<?> t : largestGraph) interestingTiles.add((AbstractAffineTile2D<?>) t);
if (param.hide_disconnected)
for (final AbstractAffineTile2D<?> t : al_tiles) if (!interestingTiles.contains(t))
t.getPatch().setVisible(false);
if (param.remove_disconnected)
for (final AbstractAffineTile2D<?> t : al_tiles) if (!interestingTiles.contains(t))
t.getPatch().remove(false);
}
// all
Display.repaint(patch[0].getLayer(), null, 0, true);
//
} catch (final Exception e) {
IJError.print(e);
}
}
};
}
use of mpicbg.models.Tile in project TrakEM2 by trakem2.
the class StitchingTEM method optimizeTileConfiguration.
/**
* Optimize tile configuration by removing bad matches
*
* @param tiles complete list of tiles
* @param fixed_tiles list of fixed tiles
* @param param phase correlation parameters
*/
public static void optimizeTileConfiguration(final ArrayList<AbstractAffineTile2D<?>> tiles, final ArrayList<AbstractAffineTile2D<?>> fixed_tiles, final PhaseCorrelationParam param) {
// Run optimization
if (fixed_tiles.isEmpty())
fixed_tiles.add(tiles.get(0));
// with default parameters
boolean proceed = true;
while (proceed) {
Align.optimizeTileConfiguration(new Align.ParamOptimize(), tiles, fixed_tiles);
/* get all transfer errors */
final ErrorStatistic e = new ErrorStatistic(tiles.size() + 1);
for (final AbstractAffineTile2D<?> t : tiles) t.update();
for (final AbstractAffineTile2D<?> t : tiles) {
for (final PointMatch p : t.getMatches()) {
e.add(p.getDistance());
}
}
/* remove the worst if there is one */
if (e.max > param.mean_factor * e.mean) {
A: for (final AbstractAffineTile2D<?> t : tiles) {
for (final PointMatch p : t.getMatches()) {
if (p.getDistance() >= e.max) {
final Tile<?> o = t.findConnectedTile(p);
t.removeConnectedTile(o);
o.removeConnectedTile(t);
// Utils.log2( "Removing bad match from configuration, error = " + e.max );
break A;
}
}
}
} else
proceed = false;
}
}
use of mpicbg.models.Tile in project TrakEM2 by trakem2.
the class ElasticLayerAlignment method exec.
/**
* @param param
* @param layerRange
* @param fixedLayers
* @param emptyLayers
* @param box
* @param filter
* @param useTps true if using TPS transforms, otherwise MLS
* @throws Exception
*/
@SuppressWarnings("deprecation")
public final void exec(final Param param, final Project project, 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 ExecutorService service = ExecutorProvider.getExecutorService(1.0f);
/* create tiles and models for all layers */
final ArrayList<Tile<?>> tiles = new ArrayList<Tile<?>>();
for (int i = 0; i < layerRange.size(); ++i) {
switch(param.desiredModelIndex) {
case 0:
tiles.add(new Tile<TranslationModel2D>(new TranslationModel2D()));
break;
case 1:
tiles.add(new Tile<RigidModel2D>(new RigidModel2D()));
break;
case 2:
tiles.add(new Tile<SimilarityModel2D>(new SimilarityModel2D()));
break;
case 3:
tiles.add(new Tile<AffineModel2D>(new AffineModel2D()));
break;
case 4:
tiles.add(new Tile<HomographyModel2D>(new HomographyModel2D()));
break;
default:
return;
}
}
/* collect all pairs of slices for which a model could be found */
final ArrayList<Triple<Integer, Integer, AbstractModel<?>>> pairs = new ArrayList<Triple<Integer, Integer, AbstractModel<?>>>();
if (!param.isAligned) {
preAlignStack(param, project, layerRange, box, filter, pairs);
} else {
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) {
pairs.add(new Triple<Integer, Integer, AbstractModel<?>>(i, j, new TranslationModel2D()));
}
}
}
/* Elastic alignment */
/* Initialization */
final TileConfiguration initMeshes = new TileConfiguration();
final int meshWidth = (int) Math.ceil(box.width * param.layerScale);
final int meshHeight = (int) Math.ceil(box.height * param.layerScale);
final ArrayList<SpringMesh> meshes = new ArrayList<SpringMesh>(layerRange.size());
for (int i = 0; i < layerRange.size(); ++i) {
meshes.add(new SpringMesh(param.resolutionSpringMesh, meshWidth, meshHeight, param.stiffnessSpringMesh, param.maxStretchSpringMesh * param.layerScale, param.dampSpringMesh));
}
// final int blockRadius = Math.max( 32, meshWidth / p.resolutionSpringMesh / 2 );
final int blockRadius = Math.max(16, mpicbg.util.Util.roundPos(param.layerScale * param.blockRadius));
Utils.log("effective block radius = " + blockRadius);
final ArrayList<Future<BlockMatchPairCallable.BlockMatchResults>> futures = new ArrayList<Future<BlockMatchPairCallable.BlockMatchResults>>(pairs.size());
for (final Triple<Integer, Integer, AbstractModel<?>> pair : pairs) {
/* free memory */
project.getLoader().releaseAll();
final SpringMesh m1 = meshes.get(pair.a);
final SpringMesh m2 = meshes.get(pair.b);
final ArrayList<Vertex> v1 = m1.getVertices();
final ArrayList<Vertex> v2 = m2.getVertices();
final Layer layer1 = layerRange.get(pair.a);
final Layer layer2 = layerRange.get(pair.b);
final boolean layer1Fixed = fixedLayers.contains(layer1);
final boolean layer2Fixed = fixedLayers.contains(layer2);
if (!(layer1Fixed && layer2Fixed)) {
final BlockMatchPairCallable bmpc = new BlockMatchPairCallable(pair, layerRange, layer1Fixed, layer2Fixed, filter, param, v1, v2, box);
futures.add(service.submit(bmpc));
}
}
for (final Future<BlockMatchPairCallable.BlockMatchResults> future : futures) {
final BlockMatchPairCallable.BlockMatchResults results = future.get();
final Collection<PointMatch> pm12 = results.pm12, pm21 = results.pm21;
final Triple<Integer, Integer, AbstractModel<?>> pair = results.pair;
final Tile<?> t1 = tiles.get(pair.a);
final Tile<?> t2 = tiles.get(pair.b);
final SpringMesh m1 = meshes.get(pair.a);
final SpringMesh m2 = meshes.get(pair.b);
final double springConstant = 1.0 / (pair.b - pair.a);
final boolean layer1Fixed = results.layer1Fixed;
final boolean layer2Fixed = results.layer2Fixed;
if (layer1Fixed) {
initMeshes.fixTile(t1);
} else {
if (param.useLocalSmoothnessFilter) {
Utils.log(pair.a + " > " + pair.b + ": " + pm12.size() + " candidates passed local smoothness filter.");
} else {
Utils.log(pair.a + " > " + pair.b + ": found " + pm12.size() + " correspondences.");
}
for (final PointMatch pm : pm12) {
final Vertex p1 = (Vertex) pm.getP1();
final Vertex p2 = new Vertex(pm.getP2());
p1.addSpring(p2, new Spring(0, springConstant));
m2.addPassiveVertex(p2);
}
/*
* adding Tiles to the initialing TileConfiguration, adding a Tile
* multiple times does not harm because the TileConfiguration is
* backed by a Set.
*/
if (pm12.size() > pair.c.getMinNumMatches()) {
initMeshes.addTile(t1);
initMeshes.addTile(t2);
t1.connect(t2, pm12);
}
}
if (layer2Fixed)
initMeshes.fixTile(t2);
else {
if (param.useLocalSmoothnessFilter) {
Utils.log(pair.a + " < " + pair.b + ": " + pm21.size() + " candidates passed local smoothness filter.");
} else {
Utils.log(pair.a + " < " + pair.b + ": found " + pm21.size() + " correspondences.");
}
for (final PointMatch pm : pm21) {
final Vertex p1 = (Vertex) pm.getP1();
final Vertex p2 = new Vertex(pm.getP2());
p1.addSpring(p2, new Spring(0, springConstant));
m1.addPassiveVertex(p2);
}
/*
* adding Tiles to the initialing TileConfiguration, adding a Tile
* multiple times does not harm because the TileConfiguration is
* backed by a Set.
*/
if (pm21.size() > pair.c.getMinNumMatches()) {
initMeshes.addTile(t1);
initMeshes.addTile(t2);
t2.connect(t1, pm21);
}
}
Utils.log(pair.a + " <> " + pair.b + " spring constant = " + springConstant);
}
/* pre-align by optimizing a piecewise linear model */
initMeshes.optimize(param.maxEpsilon * param.layerScale, param.maxIterationsSpringMesh, param.maxPlateauwidthSpringMesh);
for (int i = 0; i < layerRange.size(); ++i) meshes.get(i).init(tiles.get(i).getModel());
/* optimize the meshes */
try {
final long t0 = System.currentTimeMillis();
Utils.log("Optimizing spring meshes...");
if (param.useLegacyOptimizer) {
Utils.log(" ...using legacy optimizer...");
SpringMesh.optimizeMeshes2(meshes, param.maxEpsilon * param.layerScale, param.maxIterationsSpringMesh, param.maxPlateauwidthSpringMesh, param.visualize);
} else {
SpringMesh.optimizeMeshes(meshes, param.maxEpsilon * param.layerScale, param.maxIterationsSpringMesh, param.maxPlateauwidthSpringMesh, param.visualize);
}
Utils.log("Done optimizing spring meshes. Took " + (System.currentTimeMillis() - t0) + " ms");
} catch (final NotEnoughDataPointsException e) {
Utils.log("There were not enough data points to get the spring mesh optimizing.");
e.printStackTrace();
return;
}
/* translate relative to bounding box */
for (final SpringMesh mesh : meshes) {
for (final PointMatch pm : mesh.getVA().keySet()) {
final Point p1 = pm.getP1();
final Point p2 = pm.getP2();
final double[] l = p1.getL();
final double[] w = p2.getW();
l[0] = l[0] / param.layerScale + box.x;
l[1] = l[1] / param.layerScale + box.y;
w[0] = w[0] / param.layerScale + box.x;
w[1] = w[1] / param.layerScale + box.y;
}
}
/* free memory */
project.getLoader().releaseAll();
final Layer first = layerRange.get(0);
final List<Layer> layers = first.getParent().getLayers();
final LayerSet ls = first.getParent();
final Area infArea = AreaUtils.infiniteArea();
final List<VectorData> vectorData = new ArrayList<VectorData>();
for (final Layer layer : ls.getLayers()) {
vectorData.addAll(Utils.castCollection(layer.getDisplayables(VectorData.class, false, true), VectorData.class, true));
}
vectorData.addAll(Utils.castCollection(ls.getZDisplayables(VectorData.class, true), VectorData.class, true));
/* transfer layer transform into patch transforms and append to patches */
if (propagateTransformBefore || propagateTransformAfter) {
if (propagateTransformBefore) {
final ThinPlateSplineTransform tps = makeTPS(meshes.get(0).getVA().keySet());
final int firstLayerIndex = first.getParent().getLayerIndex(first.getId());
for (int i = 0; i < firstLayerIndex; ++i) {
applyTransformToLayer(layers.get(i), tps, filter);
for (final VectorData vd : vectorData) {
vd.apply(layers.get(i), infArea, tps);
}
}
}
if (propagateTransformAfter) {
final Layer last = layerRange.get(layerRange.size() - 1);
final CoordinateTransform ct;
if (param.useTps)
ct = makeTPS(meshes.get(meshes.size() - 1).getVA().keySet());
else {
final MovingLeastSquaresTransform2 mls = new MovingLeastSquaresTransform2();
mls.setMatches(meshes.get(meshes.size() - 1).getVA().keySet());
ct = mls;
}
final int lastLayerIndex = last.getParent().getLayerIndex(last.getId());
for (int i = lastLayerIndex + 1; i < layers.size(); ++i) {
applyTransformToLayer(layers.get(i), ct, filter);
for (final VectorData vd : vectorData) {
vd.apply(layers.get(i), infArea, ct);
}
}
}
}
for (int l = 0; l < layerRange.size(); ++l) {
IJ.showStatus("Applying transformation to patches ...");
IJ.showProgress(0, layerRange.size());
final Layer layer = layerRange.get(l);
final ThinPlateSplineTransform tps = makeTPS(meshes.get(l).getVA().keySet());
applyTransformToLayer(layer, tps, filter);
for (final VectorData vd : vectorData) {
vd.apply(layer, infArea, tps);
}
if (Thread.interrupted()) {
Utils.log("Interrupted during applying transformations to patches. No all patches have been updated. Re-generate mipmaps manually.");
}
IJ.showProgress(l + 1, layerRange.size());
}
/* update patch mipmaps */
final int firstLayerIndex;
final int lastLayerIndex;
if (propagateTransformBefore)
firstLayerIndex = 0;
else {
firstLayerIndex = first.getParent().getLayerIndex(first.getId());
}
if (propagateTransformAfter)
lastLayerIndex = layers.size() - 1;
else {
final Layer last = layerRange.get(layerRange.size() - 1);
lastLayerIndex = last.getParent().getLayerIndex(last.getId());
}
for (int i = firstLayerIndex; i <= lastLayerIndex; ++i) {
final Layer layer = layers.get(i);
if (!(emptyLayers.contains(layer) || fixedLayers.contains(layer))) {
for (final Patch patch : AlignmentUtils.filterPatches(layer, filter)) patch.updateMipMaps();
}
}
Utils.log("Done.");
}
use of mpicbg.models.Tile in project TrakEM2 by trakem2.
the class MatchIntensities method run.
/**
* @param layers
* @param radius
* @param scale
* @param numCoefficients
* @param lambda1
* @param lambda2
* @param neighborWeight
* @param roi
*/
public <M extends Model<M> & Affine1D<M>> void run(final List<Layer> layers, final int radius, final double scale, final int numCoefficients, final double lambda1, final double lambda2, final double neighborWeight, final Rectangle roi) throws InterruptedException, ExecutionException {
final int firstLayerIndex = layerset.getLayerIndex(layers.get(0).getId());
final int lastLayerIndex = layerset.getLayerIndex(layers.get(layers.size() - 1).getId());
// final PointMatchFilter filter = new RansacRegressionFilter();
final PointMatchFilter filter = new RansacRegressionReduceFilter();
/* collect patches */
Utils.log("Collecting patches ... ");
final ArrayList<Patch> patches = new ArrayList<Patch>();
for (final Layer layer : layers) patches.addAll((Collection) layer.getDisplayables(Patch.class, roi));
/* delete existing intensity coefficients */
Utils.log("Clearing existing intensity maps ... ");
for (final Patch p : patches) p.clearIntensityMap();
/* generate coefficient tiles for all patches
* TODO consider offering alternative models */
final HashMap<Patch, ArrayList<Tile<? extends M>>> coefficientsTiles = (HashMap) generateCoefficientsTiles(patches, new InterpolatedAffineModel1D<InterpolatedAffineModel1D<AffineModel1D, TranslationModel1D>, IdentityModel>(new InterpolatedAffineModel1D<AffineModel1D, TranslationModel1D>(new AffineModel1D(), new TranslationModel1D(), lambda1), new IdentityModel(), lambda2), numCoefficients * numCoefficients);
/* completed patches */
final HashSet<Patch> completedPatches = new HashSet<Patch>();
/* collect patch pairs */
Utils.log("Collecting patch pairs ... ");
final ArrayList<ValuePair<Patch, Patch>> patchPairs = new ArrayList<ValuePair<Patch, Patch>>();
for (final Patch p1 : patches) {
completedPatches.add(p1);
final Rectangle box1 = p1.getBoundingBox().intersection(roi);
final ArrayList<Patch> p2s = new ArrayList<Patch>();
/* across adjacent layers */
final int layerIndex = layerset.getLayerIndex(p1.getLayer().getId());
for (int i = Math.max(firstLayerIndex, layerIndex - radius); i <= Math.min(lastLayerIndex, layerIndex + radius); ++i) {
final Layer layer = layerset.getLayer(i);
if (layer != null)
p2s.addAll((Collection) layer.getDisplayables(Patch.class, box1));
}
for (final Patch p2 : p2s) {
/*
* if this patch had been processed earlier, all matches are
* already in
*/
if (completedPatches.contains(p2))
continue;
patchPairs.add(new ValuePair<Patch, Patch>(p1, p2));
}
}
final int numThreads = Integer.parseInt(layerset.getProperty("n_mipmap_threads", Integer.toString(Runtime.getRuntime().availableProcessors())));
Utils.log("Matching intensities using " + numThreads + " threads ... ");
final ExecutorService exec = Executors.newFixedThreadPool(numThreads);
final ArrayList<Future<?>> futures = new ArrayList<Future<?>>();
for (final ValuePair<Patch, Patch> patchPair : patchPairs) {
futures.add(exec.submit(new Matcher(roi, patchPair, (HashMap) coefficientsTiles, filter, scale, numCoefficients)));
}
for (final Future<?> future : futures) future.get();
/* connect tiles within patches */
Utils.log("Connecting coefficient tiles in the same patch ... ");
for (final Patch p1 : completedPatches) {
/* get the coefficient tiles */
final ArrayList<Tile<? extends M>> p1CoefficientsTiles = coefficientsTiles.get(p1);
for (int y = 1; y < numCoefficients; ++y) {
final int yr = numCoefficients * y;
final int yr1 = yr - numCoefficients;
for (int x = 0; x < numCoefficients; ++x) {
identityConnect(p1CoefficientsTiles.get(yr1 + x), p1CoefficientsTiles.get(yr + x), neighborWeight);
}
}
for (int y = 0; y < numCoefficients; ++y) {
final int yr = numCoefficients * y;
for (int x = 1; x < numCoefficients; ++x) {
final int yrx = yr + x;
identityConnect(p1CoefficientsTiles.get(yrx), p1CoefficientsTiles.get(yrx - 1), neighborWeight);
}
}
}
/* optimize */
Utils.log("Optimizing ... ");
final TileConfiguration tc = new TileConfiguration();
for (final ArrayList<Tile<? extends M>> coefficients : coefficientsTiles.values()) {
// for ( final Tile< ? > t : coefficients )
// if ( t.getMatches().size() == 0 )
// IJ.log( "bang" );
tc.addTiles(coefficients);
}
try {
tc.optimize(0.01f, iterations, iterations, 0.75f);
} catch (final NotEnoughDataPointsException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (final IllDefinedDataPointsException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/* save coefficients */
final double[] ab = new double[2];
final FSLoader loader = (FSLoader) layerset.getProject().getLoader();
final String itsDir = loader.getUNUIdFolder() + "trakem2.its/";
for (final Entry<Patch, ArrayList<Tile<? extends M>>> entry : coefficientsTiles.entrySet()) {
final FloatProcessor as = new FloatProcessor(numCoefficients, numCoefficients);
final FloatProcessor bs = new FloatProcessor(numCoefficients, numCoefficients);
final Patch p = entry.getKey();
final double min = p.getMin();
final double max = p.getMax();
final ArrayList<Tile<? extends M>> tiles = entry.getValue();
for (int i = 0; i < numCoefficients * numCoefficients; ++i) {
final Tile<? extends M> t = tiles.get(i);
final Affine1D<?> affine = t.getModel();
affine.toArray(ab);
/* coefficients mapping into existing [min, max] */
as.setf(i, (float) ab[0]);
bs.setf(i, (float) ((max - min) * ab[1] + min - ab[0] * min));
}
final ImageStack coefficientsStack = new ImageStack(numCoefficients, numCoefficients);
coefficientsStack.addSlice(as);
coefficientsStack.addSlice(bs);
final String itsPath = itsDir + FSLoader.createIdPath(Long.toString(p.getId()), "it", ".tif");
new File(itsPath).getParentFile().mkdirs();
IJ.saveAs(new ImagePlus("", coefficientsStack), "tif", itsPath);
}
/* update mipmaps */
for (final Patch p : patches) p.getProject().getLoader().decacheImagePlus(p.getId());
final ArrayList<Future<Boolean>> mipmapFutures = new ArrayList<Future<Boolean>>();
for (final Patch p : patches) mipmapFutures.add(p.updateMipMaps());
for (final Future<Boolean> f : mipmapFutures) f.get();
Utils.log("Matching intensities done.");
}
use of mpicbg.models.Tile 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.");
}
Aggregations