use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.
the class PatchStack method createColor256Copy.
// WARNING This method will fail if the stack has slices of different dimensions
/**
* Does not respect local transform of the patches, this is intended for confocal stacks.
*/
public ImagePlus createColor256Copy() {
final Rectangle box = patch[0].getBoundingBox();
final int width = box.width;
final int height = box.height;
Loader loader = patch[0].getProject().getLoader();
// the montage, in RGB
patch[0].getProject().getLoader().releaseToFit(4 * patch.length * width * height);
final ColorProcessor montage = new ColorProcessor(width * patch.length, height);
for (int i = 0; i < patch.length; i++) {
montage.insert(this.stack.getProcessor(i + 1), i * width, 0);
}
final MedianCut mc = new MedianCut(montage);
loader.releaseToFit(patch.length * width * height);
ImageProcessor m2 = mc.convertToByte(256);
final ImageStack st = new ImageStack(width, height);
for (int i = 0; i < patch.length; i++) {
m2.setRoi(i * width, 0, width, height);
loader.releaseToFit(width * height);
st.addSlice(null, m2.crop());
}
ImagePlus imp = new ImagePlus("color256", st);
imp.setCalibration(patch[0].getLayer().getParent().getCalibrationCopy());
// imp.getCalibration().pixelDepth = patch[0].getLayer().getThickness();
return imp;
}
use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.
the class AlignTask method alignPatches.
/**
* @param patches: the list of Patch instances to align, all belonging to the same Layer.
* @param fixedPatches: the list of Patch instances to keep locked in place, if any.
* @param m: {@link AlignTask#LINEAR_SIFT_CORRESPONDENCES}, {@link AlignTask#LINEAR_PHASE_CORRELATION} or {@link AlignTask#ELASTIC_BLOCK_CORRESPONDENCES}.
*/
public static final void alignPatches(final List<Patch> patches, final Set<Patch> fixedPatches, final int m) throws Exception {
if (patches.size() < 2) {
Utils.log("No images to align.");
return;
}
for (final Patch patch : fixedPatches) {
if (!patches.contains(patch)) {
Utils.log("The list of fixed patches contains at least one Patch not included in the list of patches to align!");
return;
}
}
if (ELASTIC_BLOCK_CORRESPONDENCES == m)
new ElasticMontage().exec(patches, fixedPatches);
else if (LINEAR_PHASE_CORRELATION == m) {
// Montage all given patches, fixedPatches is ignored!
if (!fixedPatches.isEmpty())
Utils.log("Ignoring " + fixedPatches.size() + " fixed patches.");
StitchingTEM.montageWithPhaseCorrelation(patches);
} else if (LINEAR_SIFT_CORRESPONDENCES == m) {
if (!Align.paramOptimize.setup("Montage Selection"))
return;
final GenericDialog gd = new GenericDialog("Montage Selection: Miscellaneous");
gd.addCheckbox("tiles are roughly in place", tilesAreInPlace);
gd.addCheckbox("sloppy overlap test (fast)", sloppyOverlapTest);
gd.addCheckbox("consider largest graph only", largestGraphOnly);
gd.addCheckbox("hide tiles from non-largest graph", hideDisconnectedTiles);
gd.addCheckbox("delete tiles from non-largest graph", deleteDisconnectedTiles);
gd.showDialog();
if (gd.wasCanceled())
return;
tilesAreInPlace = gd.getNextBoolean();
sloppyOverlapTest = gd.getNextBoolean();
largestGraphOnly = gd.getNextBoolean();
hideDisconnectedTiles = gd.getNextBoolean();
deleteDisconnectedTiles = gd.getNextBoolean();
final Align.ParamOptimize p = Align.paramOptimize.clone();
alignPatches(p, patches, fixedPatches, tilesAreInPlace, largestGraphOnly, hideDisconnectedTiles, deleteDisconnectedTiles, sloppyOverlapTest);
} else
Utils.log("Don't know how to align with mode " + m);
}
use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.
the class AlignTask method montageLayersTask.
/**
* Montage each layer independently.
* Does NOT register layers to each other.
* Considers visible Patches only.
*/
public static final Bureaucrat montageLayersTask(final List<Layer> layers) {
if (null == layers || layers.isEmpty())
return null;
return Bureaucrat.createAndStart(new Worker.Task("Montaging layers", true) {
@Override
public void exec() {
final int m = chooseAlignmentMode();
if (ELASTIC_BLOCK_CORRESPONDENCES == m) {
final ElasticMontage.Param p = ElasticMontage.setup();
if (p == null)
return;
else {
try {
montageLayers(p, layers);
} catch (final Exception e) {
e.printStackTrace();
Utils.log("Exception during montaging layers. Operation failed.");
}
}
} else if (LINEAR_PHASE_CORRELATION == m) {
StitchingTEM.montageWithPhaseCorrelation(layers, this);
} else if (LINEAR_SIFT_CORRESPONDENCES == m) {
if (!Align.paramOptimize.setup("Montage Layers"))
return;
final GenericDialog gd = new GenericDialog("Montage Layers: Miscellaneous");
gd.addCheckbox("tiles are roughly in place", tilesAreInPlace);
gd.addCheckbox("sloppy overlap test (fast)", sloppyOverlapTest);
gd.addCheckbox("consider largest graph only", largestGraphOnly);
gd.addCheckbox("hide tiles from non-largest graph", hideDisconnectedTiles);
gd.addCheckbox("delete tiles from non-largest graph", deleteDisconnectedTiles);
gd.showDialog();
if (gd.wasCanceled())
return;
tilesAreInPlace = gd.getNextBoolean();
sloppyOverlapTest = gd.getNextBoolean();
largestGraphOnly = gd.getNextBoolean();
hideDisconnectedTiles = gd.getNextBoolean();
deleteDisconnectedTiles = gd.getNextBoolean();
final Align.ParamOptimize p = Align.paramOptimize.clone();
montageLayers(p, layers, tilesAreInPlace, largestGraphOnly, hideDisconnectedTiles, deleteDisconnectedTiles, sloppyOverlapTest);
} else
Utils.log("Don't know how to align with mode " + m);
}
}, layers.get(0).getProject());
}
use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.
the class ElasticMontage method exec.
public final void exec(final List<Patch> patches, final Set<Patch> fixedPatches) throws Exception {
/* make sure that passed patches are ok */
if (patches.size() < 2) {
Utils.log("Elastic montage requires at least 2 patches to be montaged. You passed me " + patches.size());
return;
}
final Project project = patches.get(0).getProject();
for (final Patch patch : patches) {
if (patch.getProject() != project) {
Utils.log("Elastic montage requires all patches to be member of a single project. You passed me patches from several projects.");
return;
}
}
for (final Patch patch : fixedPatches) {
if (patch.getProject() != project) {
Utils.log("Elastic montage requires all fixed patches to be member of a single project. You passed me fixed patches from several projects.");
return;
}
}
final Param param = setup();
if (param == null)
return;
else
exec(param, patches, fixedPatches);
}
use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.
the class ElasticMontage method exec.
@SuppressWarnings("deprecation")
public final void exec(final Param param, final List<Patch> patches, final Set<Patch> fixedPatches) throws Exception {
/* free memory */
patches.get(0).getProject().getLoader().releaseAll();
/* create tiles and models for all patches */
final ArrayList<AbstractAffineTile2D<?>> tiles = new ArrayList<AbstractAffineTile2D<?>>();
final ArrayList<AbstractAffineTile2D<?>> fixedTiles = new ArrayList<AbstractAffineTile2D<?>>();
Align.tilesFromPatches(param.po, patches, fixedPatches, tiles, fixedTiles);
if (!param.isAligned) {
Align.alignTiles(param.po, tiles, fixedTiles, param.tilesAreInPlace, param.maxNumThreads);
/* Apply the estimated affine transform to patches */
for (final AbstractAffineTile2D<?> t : tiles) t.getPatch().setAffineTransform(t.createAffine());
Display.update();
}
/* generate tile pairs for all by now overlapping tiles */
final ArrayList<AbstractAffineTile2D<?>[]> tilePairs = new ArrayList<AbstractAffineTile2D<?>[]>();
AbstractAffineTile2D.pairOverlappingTiles(tiles, tilePairs);
/* check if there was any pair */
if (tilePairs.size() == 0) {
Utils.log("Elastic montage could not find any overlapping patches after pre-montaging.");
return;
}
Utils.log(tilePairs.size() + " pairs of patches will be block-matched...");
/* make pairwise global models local */
final ArrayList<Triple<AbstractAffineTile2D<?>, AbstractAffineTile2D<?>, InvertibleCoordinateTransform>> pairs = new ArrayList<Triple<AbstractAffineTile2D<?>, AbstractAffineTile2D<?>, InvertibleCoordinateTransform>>();
/*
* The following casting madness is necessary to get this code compiled
* with Sun/Oracle Java 6 which otherwise generates an inconvertible
* type exception.
*
* TODO Remove as soon as this bug is fixed in Sun/Oracle javac.
*/
for (final AbstractAffineTile2D<?>[] pair : tilePairs) {
final AbstractAffineModel2D<?> m;
switch(param.po.desiredModelIndex) {
case 0:
final TranslationModel2D t = (TranslationModel2D) (Object) pair[1].getModel().createInverse();
t.concatenate((TranslationModel2D) (Object) pair[0].getModel());
m = t;
break;
case 1:
final RigidModel2D r = (RigidModel2D) (Object) pair[1].getModel().createInverse();
r.concatenate((RigidModel2D) (Object) pair[0].getModel());
m = r;
break;
case 2:
final SimilarityModel2D s = (SimilarityModel2D) (Object) pair[1].getModel().createInverse();
s.concatenate((SimilarityModel2D) (Object) pair[0].getModel());
m = s;
break;
case 3:
final AffineModel2D a = (AffineModel2D) (Object) pair[1].getModel().createInverse();
a.concatenate((AffineModel2D) (Object) pair[0].getModel());
m = a;
break;
default:
m = null;
}
pairs.add(new Triple<AbstractAffineTile2D<?>, AbstractAffineTile2D<?>, InvertibleCoordinateTransform>(pair[0], pair[1], m));
}
/* Elastic alignment */
/* Initialization */
final double springTriangleHeightTwice = 2 * Math.sqrt(0.75 * param.springLengthSpringMesh * param.springLengthSpringMesh);
final ArrayList<SpringMesh> meshes = new ArrayList<SpringMesh>(tiles.size());
final HashMap<AbstractAffineTile2D<?>, SpringMesh> tileMeshMap = new HashMap<AbstractAffineTile2D<?>, SpringMesh>();
for (final AbstractAffineTile2D<?> tile : tiles) {
final double w = tile.getWidth();
final double h = tile.getHeight();
final int numX = Math.max(2, (int) Math.ceil(w / param.springLengthSpringMesh) + 1);
final int numY = Math.max(2, (int) Math.ceil(h / springTriangleHeightTwice) + 1);
final double wMesh = (numX - 1) * param.springLengthSpringMesh;
final double hMesh = (numY - 1) * springTriangleHeightTwice;
final SpringMesh mesh = new SpringMesh(numX, numY, wMesh, hMesh, param.stiffnessSpringMesh, param.maxStretchSpringMesh * param.bmScale, param.dampSpringMesh);
meshes.add(mesh);
tileMeshMap.put(tile, mesh);
}
// final int blockRadius = Math.max( 32, Util.roundPos( param.springLengthSpringMesh / 2 ) );
final int blockRadius = Math.max(Util.roundPos(16 / param.bmScale), param.bmBlockRadius);
/**
* TODO set this something more than the largest error by the approximate model
*/
final int searchRadius = param.bmSearchRadius;
final AbstractModel<?> localSmoothnessFilterModel = mpicbg.trakem2.align.Util.createModel(param.bmLocalModelIndex);
for (final Triple<AbstractAffineTile2D<?>, AbstractAffineTile2D<?>, InvertibleCoordinateTransform> pair : pairs) {
final AbstractAffineTile2D<?> t1 = pair.a;
final AbstractAffineTile2D<?> t2 = pair.b;
final SpringMesh m1 = tileMeshMap.get(t1);
final SpringMesh m2 = tileMeshMap.get(t2);
final ArrayList<PointMatch> pm12 = new ArrayList<PointMatch>();
final ArrayList<PointMatch> pm21 = new ArrayList<PointMatch>();
final ArrayList<Vertex> v1 = m1.getVertices();
final ArrayList<Vertex> v2 = m2.getVertices();
final String patchName1 = patchName(t1.getPatch());
final String patchName2 = patchName(t2.getPatch());
final PatchImage pi1 = t1.getPatch().createTransformedImage();
if (pi1 == null) {
Utils.log("Patch `" + patchName1 + "' failed generating a transformed image. Skipping...");
continue;
}
final PatchImage pi2 = t2.getPatch().createTransformedImage();
if (pi2 == null) {
Utils.log("Patch `" + patchName2 + "' failed generating a transformed image. Skipping...");
continue;
}
final FloatProcessor fp1 = (FloatProcessor) pi1.target.convertToFloat();
final ByteProcessor mask1 = pi1.getMask();
final FloatProcessor fpMask1 = mask1 == null ? null : scaleByte(mask1);
final FloatProcessor fp2 = (FloatProcessor) pi2.target.convertToFloat();
final ByteProcessor mask2 = pi2.getMask();
final FloatProcessor fpMask2 = mask2 == null ? null : scaleByte(mask2);
if (!fixedTiles.contains(t1)) {
BlockMatching.matchByMaximalPMCC(fp1, fp2, fpMask1, fpMask2, param.bmScale, pair.c, blockRadius, blockRadius, searchRadius, searchRadius, param.bmMinR, param.bmRodR, param.bmMaxCurvatureR, v1, pm12, new ErrorStatistic(1));
if (param.bmUseLocalSmoothnessFilter) {
Utils.log("`" + patchName1 + "' > `" + patchName2 + "': found " + pm12.size() + " correspondence candidates.");
localSmoothnessFilterModel.localSmoothnessFilter(pm12, pm12, param.bmLocalRegionSigma, param.bmMaxLocalEpsilon, param.bmMaxLocalTrust);
Utils.log("`" + patchName1 + "' > `" + patchName2 + "': " + pm12.size() + " candidates passed local smoothness filter.");
} else {
Utils.log("`" + patchName1 + "' > `" + patchName2 + "': found " + pm12.size() + " correspondences.");
}
} else {
Utils.log("Skipping fixed patch `" + patchName1 + "'.");
}
if (!fixedTiles.contains(t2)) {
BlockMatching.matchByMaximalPMCC(fp2, fp1, fpMask2, fpMask1, param.bmScale, pair.c.createInverse(), blockRadius, blockRadius, searchRadius, searchRadius, param.bmMinR, param.bmRodR, param.bmMaxCurvatureR, v2, pm21, new ErrorStatistic(1));
if (param.bmUseLocalSmoothnessFilter) {
Utils.log("`" + patchName1 + "' < `" + patchName2 + "': found " + pm21.size() + " correspondence candidates.");
localSmoothnessFilterModel.localSmoothnessFilter(pm21, pm21, param.bmLocalRegionSigma, param.bmMaxLocalEpsilon, param.bmMaxLocalTrust);
Utils.log("`" + patchName1 + "' < `" + patchName2 + "': " + pm21.size() + " candidates passed local smoothness filter.");
} else {
Utils.log("`" + patchName1 + "' < `" + patchName2 + "': found " + pm21.size() + " correspondences.");
}
} else {
Utils.log("Skipping fixed patch `" + patchName2 + "'.");
}
for (final PointMatch pm : pm12) {
final Vertex p1 = (Vertex) pm.getP1();
final Vertex p2 = new Vertex(pm.getP2());
p1.addSpring(p2, new Spring(0, 1.0f));
m2.addPassiveVertex(p2);
}
for (final PointMatch pm : pm21) {
final Vertex p1 = (Vertex) pm.getP1();
final Vertex p2 = new Vertex(pm.getP2());
p1.addSpring(p2, new Spring(0, 1.0f));
m1.addPassiveVertex(p2);
}
}
/* initialize */
for (final Map.Entry<AbstractAffineTile2D<?>, SpringMesh> entry : tileMeshMap.entrySet()) entry.getValue().init(entry.getKey().getModel());
/* optimize the meshes */
try {
final long t0 = System.currentTimeMillis();
IJ.log("Optimizing spring meshes...");
if (param.useLegacyOptimizer) {
Utils.log(" ...using legacy optimizer...");
SpringMesh.optimizeMeshes2(meshes, param.po.maxEpsilon, param.maxIterationsSpringMesh, param.maxPlateauwidthSpringMesh, param.visualize);
} else {
SpringMesh.optimizeMeshes(meshes, param.po.maxEpsilon, param.maxIterationsSpringMesh, param.maxPlateauwidthSpringMesh, param.visualize);
}
IJ.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;
}
/* apply */
for (final Map.Entry<AbstractAffineTile2D<?>, SpringMesh> entry : tileMeshMap.entrySet()) {
final AbstractAffineTile2D<?> tile = entry.getKey();
if (!fixedTiles.contains(tile)) {
final Patch patch = tile.getPatch();
final SpringMesh mesh = entry.getValue();
final Set<PointMatch> matches = mesh.getVA().keySet();
Rectangle box = patch.getCoordinateTransformBoundingBox();
/* compensate for existing coordinate transform bounding box */
for (final PointMatch pm : matches) {
final Point p1 = pm.getP1();
final double[] l = p1.getL();
l[0] += box.x;
l[1] += box.y;
}
final ThinPlateSplineTransform mlt = ElasticLayerAlignment.makeTPS(matches);
patch.appendCoordinateTransform(mlt);
box = patch.getCoordinateTransformBoundingBox();
patch.getAffineTransform().setToTranslation(box.x, box.y);
patch.updateInDatabase("transform");
patch.updateBucket();
patch.updateMipMaps();
}
}
Utils.log("Done.");
}
Aggregations