From 8b795b103d2576b22d356701331eb1e585fe407d Mon Sep 17 00:00:00 2001 From: rimadoma Date: Sat, 25 Apr 2020 15:24:11 +0100 Subject: [PATCH 1/4] Add calibrated mesh --- .../net/imagej/ops/geom/GeomNamespace.java | 14 +++++++- .../ops/geom/geom3d/DefaultMarchingCubes.java | 32 ++++++++++++++++- .../net/imagej/ops/geom/MeshFeatureTests.java | 36 +++++++++++++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/imagej/ops/geom/GeomNamespace.java b/src/main/java/net/imagej/ops/geom/GeomNamespace.java index 9acd9d7271..c732c3866d 100644 --- a/src/main/java/net/imagej/ops/geom/GeomNamespace.java +++ b/src/main/java/net/imagej/ops/geom/GeomNamespace.java @@ -31,6 +31,7 @@ import java.util.List; +import net.imagej.axis.CalibratedAxis; import net.imagej.mesh.Mesh; import net.imagej.ops.AbstractNamespace; import net.imagej.ops.Namespace; @@ -497,7 +498,18 @@ public > Mesh marchingCubes( net.imagej.ops.Ops.Geometric.MarchingCubes.class, in, isolevel, interpolatorClass); return result; - } + } + + @OpMethod(op = net.imagej.ops.geom.geom3d.DefaultMarchingCubes.class) + public > Mesh marchingCubes( + final RandomAccessibleInterval in, final double isolevel, + final VertexInterpolator interpolatorClass, final List axes) + { + final Mesh result = (Mesh) ops().run( + net.imagej.ops.Ops.Geometric.MarchingCubes.class, in, isolevel, + interpolatorClass, axes); + return result; + } @OpMethod(op = net.imagej.ops.geom.geom3d.DefaultMedianElongation.class) public DoubleType medianElongation(final Mesh in) { diff --git a/src/main/java/net/imagej/ops/geom/geom3d/DefaultMarchingCubes.java b/src/main/java/net/imagej/ops/geom/geom3d/DefaultMarchingCubes.java index e63daaed9f..997b80b4ea 100644 --- a/src/main/java/net/imagej/ops/geom/geom3d/DefaultMarchingCubes.java +++ b/src/main/java/net/imagej/ops/geom/geom3d/DefaultMarchingCubes.java @@ -29,7 +29,11 @@ package net.imagej.ops.geom.geom3d; +import java.util.List; + +import net.imagej.axis.CalibratedAxis; import net.imagej.mesh.Mesh; +import net.imagej.mesh.Triangles; import net.imagej.mesh.naive.NaiveDoubleMesh; import net.imagej.ops.Contingent; import net.imagej.ops.Ops; @@ -55,6 +59,7 @@ * lookup tables are from his implementation. * * @author Tim-Oliver Buchholz (University of Konstanz) + * @author Richard Domander * @param BooleanType */ @Plugin(type = Ops.Geometric.MarchingCubes.class) @@ -70,6 +75,10 @@ public class DefaultMarchingCubes> extends private VertexInterpolator interpolatorClass = new DefaultVertexInterpolator(); + /** If not null, output mesh coordinates are calibrated */ + @Parameter(type = ItemIO.INPUT, required = false) + private List axes; + @SuppressWarnings({ "unchecked" }) @Override public Mesh calculate(final RandomAccessibleInterval input) { @@ -181,7 +190,14 @@ public Mesh calculate(final RandomAccessibleInterval input) { final double v2y = vertlist[TRIANGLE_TABLE[cubeindex][i]][1]; final double v2z = vertlist[TRIANGLE_TABLE[cubeindex][i]][2]; if (positiveArea(v0x, v0y, v0z, v1x, v1y, v1z, v2x, v2y, v2z)) { - output.triangles().add(v0x, v0y, v0z, v1x, v1y, v1z, v2x, v2y, v2z); + if (axes != null) { + addCalibrated(output.triangles(), v0x, v0y, v0z, + v1x, v1y, v1z, v2x, v2y, v2z); + } else { + output.triangles() + .add(v0x, v0y, v0z, v1x, v1y, v1z, v2x, v2y, + v2z); + } } } } @@ -189,6 +205,20 @@ public Mesh calculate(final RandomAccessibleInterval input) { return output; } + private void addCalibrated(final Triangles triangles, final double v0x, + final double v0y, final double v0z, final double v1x, + final double v1y, final double v1z, final double v2x, + final double v2y, final double v2z) { + final CalibratedAxis xAxis = axes.get(0); + final CalibratedAxis yAxis = axes.get(1); + final CalibratedAxis zAxis = axes.get(2); + triangles.add(xAxis.calibratedValue(v0x), yAxis.calibratedValue(v0y), + zAxis.calibratedValue(v0z), xAxis.calibratedValue(v1x), + yAxis.calibratedValue(v1y), zAxis.calibratedValue(v1z), + xAxis.calibratedValue(v2x), yAxis.calibratedValue(v2y), + zAxis.calibratedValue(v2z)); + } + private boolean positiveArea(double v0x, double v0y, double v0z, // double v1x, double v1y, double v1z, // double v2x, double v2y, double v2z) diff --git a/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java b/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java index e972aa4bb9..05866e8710 100644 --- a/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java +++ b/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java @@ -33,6 +33,11 @@ import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import net.imagej.axis.CalibratedAxis; +import net.imagej.axis.DefaultLinearAxis; import net.imagej.mesh.Mesh; import net.imagej.mesh.Triangle; import net.imagej.ops.Ops; @@ -52,6 +57,7 @@ import net.imagej.ops.geom.geom3d.DefaultVerticesCountMesh; import net.imagej.ops.geom.geom3d.DefaultVolumeConvexHullMesh; import net.imagej.ops.geom.geom3d.DefaultVolumeMesh; +import net.imagej.ops.geom.geom3d.mesh.DefaultVertexInterpolator; import net.imglib2.roi.labeling.LabelRegion; import net.imglib2.type.numeric.real.DoubleType; @@ -128,6 +134,36 @@ public void marchingCubes() { assertTrue(!expectedFacets.hasNext() && !actualFacets.hasNext()); } + @Test + public void marchingCubesCalibratedMesh() { + final double sx = 1.0; + final double sy = 0.5; + final double sz = 0.25; + final List axes = Stream + .of(new DefaultLinearAxis(sx), new DefaultLinearAxis(sy), + new DefaultLinearAxis(sz)).collect(Collectors.toList()); + final Iterator meshFacets = mesh.triangles().iterator(); + + final Mesh result = ops.geom() + .marchingCubes(ROI, 1, new DefaultVertexInterpolator(), axes); + + assertEquals(mesh.triangles().size(), result.triangles().size()); + final Iterator actualFacets = result.triangles().iterator(); + while (meshFacets.hasNext() && actualFacets.hasNext()) { + final Triangle mesh = meshFacets.next(); + final Triangle actual = actualFacets.next(); + assertEquals(mesh.v0x() * sx, actual.v0x(), EPSILON); + assertEquals(mesh.v0y() * sy, actual.v0y(), EPSILON); + assertEquals(mesh.v0z() * sz, actual.v0z(), EPSILON); + assertEquals(mesh.v1x() * sx, actual.v1x(), EPSILON); + assertEquals(mesh.v1y() * sy, actual.v1y(), EPSILON); + assertEquals(mesh.v1z() * sz, actual.v1z(), EPSILON); + assertEquals(mesh.v2x() * sx, actual.v2x(), EPSILON); + assertEquals(mesh.v2y() * sy, actual.v2y(), EPSILON); + assertEquals(mesh.v2z() * sz, actual.v2z(), EPSILON); + } + } + @Test public void medianElongation() { // formula verified and ground truth computed with matlab From d8706c103b6c0318d3f56fcf0e3dc8425ce487c4 Mon Sep 17 00:00:00 2001 From: rimadoma Date: Sat, 25 Apr 2020 15:25:15 +0100 Subject: [PATCH 2/4] Add Javadoc to test class --- src/test/java/net/imagej/ops/geom/MeshFeatureTests.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java b/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java index 05866e8710..8a337c778b 100644 --- a/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java +++ b/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java @@ -64,6 +64,12 @@ import org.junit.BeforeClass; import org.junit.Test; +/** + * Tests for mesh related ops + * + * @author Tim-Oliver Buchholz (University of Konstanz) + * @author Richard Domander + */ public class MeshFeatureTests extends AbstractFeatureTest { private static final double EPSILON = 10e-12; private static LabelRegion ROI; From 1c3f1ed633c514a1ebd3df36c35d6ce022451299 Mon Sep 17 00:00:00 2001 From: rimadoma Date: Sat, 25 Apr 2020 15:26:44 +0100 Subject: [PATCH 3/4] Fix dangling Javadoc --- src/test/java/net/imagej/ops/geom/MeshFeatureTests.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java b/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java index 8a337c778b..198c504d18 100644 --- a/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java +++ b/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java @@ -97,12 +97,11 @@ public void compactness() { ((DoubleType) ops.run(DefaultCompactness.class, mesh)).get(), EPSILON); } + /** + * ConvexHull3D is tested in {@link QuickHull3DTest}. + */ @Test - public void convexHull3D() { - /** - * convexHull3D is tested in {@link QuickHull3DTest}. - */ - } + public void convexHull3D() {} @Test public void convexityMesh() { From f9f5642480b560996112b545bf58907ea617642c Mon Sep 17 00:00:00 2001 From: rimadoma Date: Sat, 25 Apr 2020 15:28:05 +0100 Subject: [PATCH 4/4] Free test resources --- src/test/java/net/imagej/ops/geom/MeshFeatureTests.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java b/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java index 198c504d18..89e4185915 100644 --- a/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java +++ b/src/test/java/net/imagej/ops/geom/MeshFeatureTests.java @@ -61,6 +61,7 @@ import net.imglib2.roi.labeling.LabelRegion; import net.imglib2.type.numeric.real.DoubleType; +import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -81,6 +82,12 @@ public static void setupBefore() { mesh = getMesh(); } + @AfterClass + public static void oneTimeTearDown() { + mesh = null; + ROI = null; + } + @Test public void boxivityMesh() { try {