use of mpicbg.models.AffineModel2D in project TrakEM2 by trakem2.
the class TransformMeshMappingWithMasks method map.
/**
* Render source into target using alpha composition.
* Interpolation is specified by the interpolation methods
* set in source and alpha.
*
* @param source
* @param alpha
* @param target
* @param numThreads
*/
public final void map(final ShortProcessor source, final ByteProcessor alpha, final ShortProcessor target, final int numThreads) {
final List<AffineModel2D> l = new ArrayList<AffineModel2D>();
l.addAll(transform.getAV().keySet());
final AtomicInteger i = new AtomicInteger(0);
final ArrayList<Thread> threads = new ArrayList<Thread>(numThreads);
for (int k = 0; k < numThreads; ++k) {
final Thread mtt = new MapShortAlphaTriangleThread(i, l, transform, source, alpha, target);
threads.add(mtt);
mtt.start();
}
for (final Thread mtt : threads) {
try {
mtt.join();
} catch (final InterruptedException e) {
}
}
}
use of mpicbg.models.AffineModel2D in project TrakEM2 by trakem2.
the class MovingLeastSquaresTransform2 method init.
@Override
public final void init(final String data) throws NumberFormatException {
final String[] fields = data.split("\\s+");
if (fields.length > 3) {
final int n = Integer.parseInt(fields[1]);
if ((fields.length - 3) % (2 * n + 1) == 0) {
final int l = (fields.length - 3) / (2 * n + 1);
if (n == 2) {
if (fields[0].equals("translation"))
model = new TranslationModel2D();
else if (fields[0].equals("rigid"))
model = new RigidModel2D();
else if (fields[0].equals("similarity"))
model = new SimilarityModel2D();
else if (fields[0].equals("affine"))
model = new AffineModel2D();
else
throw new NumberFormatException("Inappropriate parameters for " + this.getClass().getCanonicalName());
} else if (n == 3) {
if (fields[0].equals("affine"))
model = new AffineModel3D();
else
throw new NumberFormatException("Inappropriate parameters for " + this.getClass().getCanonicalName());
} else
throw new NumberFormatException("Inappropriate parameters for " + this.getClass().getCanonicalName());
alpha = Float.parseFloat(fields[2]);
p = new float[n][l];
q = new float[n][l];
w = new float[l];
int i = 2, j = 0;
while (i < fields.length - 1) {
for (int d = 0; d < n; ++d) p[d][j] = Float.parseFloat(fields[++i]);
for (int d = 0; d < n; ++d) q[d][j] = Float.parseFloat(fields[++i]);
w[j] = Float.parseFloat(fields[++i]);
++j;
}
} else
throw new NumberFormatException("Inappropriate parameters for " + this.getClass().getCanonicalName());
} else
throw new NumberFormatException("Inappropriate parameters for " + this.getClass().getCanonicalName());
}
use of mpicbg.models.AffineModel2D in project TrakEM2 by trakem2.
the class ManualAlignMode method apply.
@Override
public boolean apply() {
// Check there's more than one layer
if (m.size() < 2) {
Utils.showMessage("Need more than one layer to align!");
return false;
}
// Check that the current layer is one of the layers with landmarks.
// Will be used as reference
final Layer ref_layer = display.getLayer();
if (null == m.get(ref_layer)) {
Utils.showMessage("Please scroll to a layer with landmarks,\nto be used as reference.");
return false;
}
// Check that all layers have the same number of landmarks
int n_landmarks = -1;
for (final Map.Entry<Layer, Landmarks> e : m.entrySet()) {
final Landmarks lm = e.getValue();
if (-1 == n_landmarks) {
n_landmarks = lm.points.size();
continue;
}
if (n_landmarks != lm.points.size()) {
Utils.showMessage("Can't apply: there are different amounts of landmarks per layer.\nSee the log window.");
for (final Map.Entry<Layer, Landmarks> ee : m.entrySet()) {
Utils.log(ee.getValue().points.size() + " landmarks in layer " + ee.getKey());
}
return false;
}
}
// Sort Layers by Z
final TreeMap<Layer, Landmarks> sorted = new TreeMap<Layer, Landmarks>(new Comparator<Layer>() {
@Override
public boolean equals(final Object ob) {
return this == ob;
}
@Override
public int compare(final Layer l1, final Layer l2) {
// Ascending order
final double dz = l1.getZ() - l2.getZ();
if (dz < 0)
return -1;
else if (dz > 0)
return 1;
else
return 0;
}
});
sorted.putAll(m);
int iref = 0;
for (final Layer la : sorted.keySet()) {
if (la != ref_layer)
iref++;
else
break;
}
// Ok, now ask for a model
final GenericDialog gd = new GenericDialog("Model");
gd.addChoice("Model:", Align.Param.modelStrings, Align.Param.modelStrings[1]);
gd.addCheckbox("Propagate to first layer", 0 != iref);
((Component) gd.getCheckboxes().get(0)).setEnabled(0 != iref);
gd.addCheckbox("Propagate to last layer", sorted.size() - 1 != iref);
((Component) gd.getCheckboxes().get(1)).setEnabled(sorted.size() - 1 != iref);
gd.showDialog();
if (gd.wasCanceled())
return false;
final int model_index = gd.getNextChoiceIndex();
final boolean propagate_to_first = gd.getNextBoolean();
final boolean propagate_to_last = gd.getNextBoolean();
int min;
// Create a model as desired
final AbstractAffineModel2D<?> model;
switch(model_index) {
case 0:
min = 1;
model = new TranslationModel2D();
break;
case 1:
min = 2;
model = new RigidModel2D();
break;
case 2:
min = 2;
model = new SimilarityModel2D();
break;
case 3:
min = 3;
model = new AffineModel2D();
break;
default:
Utils.log("Unknown model index!");
return false;
}
if (n_landmarks < min) {
Utils.showMessage("Need at least " + min + " landmarks for a " + Align.Param.modelStrings[model_index] + " model");
return false;
}
Bureaucrat.createAndStart(new Worker.Task("Aligning layers with landmarks") {
@Override
public void exec() {
// Find layers with landmarks, in increasing Z.
// Match in pairs.
// So, get two submaps: from ref_layer to first, and from ref_layer to last
// strictly lower Z than ref_layer
final SortedMap<Layer, Landmarks> first_chunk_ = new TreeMap<Layer, Landmarks>(sorted.headMap(ref_layer));
// .. so add ref_layer
first_chunk_.put(ref_layer, m.get(ref_layer));
// equal or larger Z than ref_layer
final SortedMap<Layer, Landmarks> second_chunk = sorted.tailMap(ref_layer);
final SortedMap<Layer, Landmarks> first_chunk;
// Reverse order of first_chunk
if (first_chunk_.size() > 1) {
final SortedMap<Layer, Landmarks> fc = new TreeMap<Layer, Landmarks>(new Comparator<Layer>() {
@Override
public boolean equals(final Object ob) {
return this == ob;
}
@Override
public int compare(final Layer l1, final Layer l2) {
// Descending order
final double dz = l2.getZ() - l1.getZ();
if (dz < 0)
return -1;
else if (dz > 0)
return 1;
else
return 0;
}
});
fc.putAll(first_chunk_);
first_chunk = fc;
} else {
first_chunk = first_chunk_;
}
final LayerSet ls = ref_layer.getParent();
final Collection<Layer> affected_layers = new HashSet<Layer>(m.keySet());
// Gather all Patch instances that will be affected
final ArrayList<Patch> patches = new ArrayList<Patch>();
for (final Layer la : m.keySet()) patches.addAll(la.getAll(Patch.class));
if (propagate_to_first && first_chunk.size() > 1) {
final Collection<Layer> affected = ls.getLayers().subList(0, ls.indexOf(first_chunk.lastKey()));
for (final Layer la : affected) {
patches.addAll(la.getAll(Patch.class));
}
affected_layers.addAll(affected);
}
if (propagate_to_last && second_chunk.size() > 1) {
final Collection<Layer> affected = ls.getLayers().subList(ls.indexOf(second_chunk.lastKey()) + 1, ls.size());
for (final Layer la : affected) {
patches.addAll(la.getAll(Patch.class));
}
}
// Transform segmentations along with patches
AlignTask.transformPatchesAndVectorData(patches, new Runnable() {
@Override
public void run() {
// Apply!
// TODO: when adding non-linear transforms, use this single line for undo instead of all below:
// (these transforms may be non-linear as well, which alter mipmaps.)
// ls.addTransformStepWithData(affected_layers);
// Setup undo:
// Find all images in the range of affected layers,
// plus all Displayable of those layers (but Patch instances in a separate DoTransforms step,
// to avoid adding a "data" undo for them, which would recreate mipmaps when undone).
// plus all ZDisplayable that paint in those layers
final HashSet<Displayable> ds = new HashSet<Displayable>();
final ArrayList<Displayable> patches = new ArrayList<Displayable>();
for (final Layer layer : affected_layers) {
for (final Displayable d : layer.getDisplayables()) {
if (d.getClass() == Patch.class) {
patches.add(d);
} else {
ds.add(d);
}
}
}
for (final ZDisplayable zd : ls.getZDisplayables()) {
for (final Layer layer : affected_layers) {
if (zd.paintsAt(layer)) {
ds.add((Displayable) zd);
break;
}
}
}
if (ds.size() > 0) {
final Displayable.DoEdits step = ls.addTransformStepWithData(ds);
if (patches.size() > 0) {
final ArrayList<DoStep> a = new ArrayList<DoStep>();
a.add(new Displayable.DoTransforms().addAll(patches));
step.addDependents(a);
}
}
if (first_chunk.size() > 1) {
final AffineTransform aff = align(first_chunk, model);
if (propagate_to_first) {
for (final Layer la : ls.getLayers().subList(0, ls.indexOf(first_chunk.lastKey()))) {
// exclusive last
la.apply(Patch.class, aff);
}
}
}
if (second_chunk.size() > 1) {
final AffineTransform aff = align(second_chunk, model);
if (propagate_to_last) {
for (final Layer la : ls.getLayers().subList(ls.indexOf(second_chunk.lastKey()) + 1, ls.size())) {
// exclusive last
la.apply(Patch.class, aff);
}
}
}
Display.repaint();
// Store current state
if (ds.size() > 0) {
final Displayable.DoEdits step2 = ls.addTransformStepWithData(ds);
if (patches.size() > 0) {
final ArrayList<DoStep> a2 = new ArrayList<DoStep>();
a2.add(new Displayable.DoTransforms().addAll(patches));
step2.addDependents(a2);
}
}
}
});
}
}, display.getProject());
return true;
}
use of mpicbg.models.AffineModel2D in project TrakEM2 by trakem2.
the class Stack method getBounds.
@Override
protected Rectangle getBounds(final Rectangle rect) {
final AffineModel2D a = new AffineModel2D();
a.set(at);
final double[] rMin = new double[] { Double.MAX_VALUE, Double.MAX_VALUE };
final double[] rMax = new double[] { -Double.MAX_VALUE, -Double.MAX_VALUE };
final double[] l = new double[] { boundsMin[0], boundsMin[1] };
a.applyInPlace(l);
Util.min(rMin, l);
Util.max(rMax, l);
l[0] = boundsMin[0];
l[1] = boundsMax[1];
a.applyInPlace(l);
Util.min(rMin, l);
Util.max(rMax, l);
l[0] = boundsMax[0];
l[1] = boundsMin[1];
a.applyInPlace(l);
Util.min(rMin, l);
Util.max(rMax, l);
l[0] = boundsMax[0];
l[1] = boundsMax[1];
a.applyInPlace(l);
Util.min(rMin, l);
Util.max(rMax, l);
rect.x = (int) rMin[0];
rect.y = (int) rMin[1];
rect.width = (int) Math.ceil(rMax[0] - rect.x);
rect.height = (int) Math.ceil(rMax[1] - rect.y);
return rect;
}
use of mpicbg.models.AffineModel2D in project TrakEM2 by trakem2.
the class TransformMesh method applyInverseInPlace.
/**
* Catch non-invertible locations outside of the meshes boundaries and
* transfer them with the affine defined by the `closest' affine (the affine
* whose summed up control points distances to location are smallest).
*/
@Override
public void applyInverseInPlace(final double[] location) throws NoninvertibleModelException {
assert location.length == 2 : "2d transform meshs can be applied to 2d points only.";
final Set<AffineModel2D> s = av.keySet();
for (final AffineModel2D ai : s) {
final ArrayList<PointMatch> pm = av.get(ai);
if (isInConvexTargetPolygon(pm, location)) {
ai.applyInverseInPlace(location);
return;
}
}
/* not in the mesh, find the closest affine */
double dMin = Double.MAX_VALUE;
AffineModel2D closestAffine = new AffineModel2D();
final double x = location[0];
final double y = location[1];
for (final AffineModel2D ai : s) {
final ArrayList<PointMatch> pm = av.get(ai);
double d = 0;
for (final PointMatch p : pm) {
final double[] w = p.getP2().getW();
final double dx = w[0] - x;
final double dy = w[1] - y;
d += Math.sqrt(dx * dx + dy * dy);
}
if (d < dMin) {
dMin = d;
closestAffine = ai;
}
}
closestAffine.applyInverseInPlace(location);
throw new NoninvertibleModelException("Mesh external location ( " + x + ", " + y + " ) transferred to ( " + location[0] + ", " + location[1] + " ) by closest affine.");
}
Aggregations