Skip to content

Commit 6e77970

Browse files
committed
WIP: Elongation and Centroid work
1 parent 9764de4 commit 6e77970

File tree

3 files changed

+167
-2
lines changed

3 files changed

+167
-2
lines changed

src/main/java/net/imglib2/mesh/MeshStats.java

Lines changed: 149 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@
2929
package net.imglib2.mesh;
3030

3131
import net.imglib2.mesh.alg.InertiaTensor;
32+
import net.imglib2.type.numeric.real.DoubleType;
3233
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
3334

3435
import net.imglib2.RealPoint;
3536
import net.imglib2.mesh.alg.hull.ConvexHull;
3637
import net.imglib2.mesh.util.MeshUtil;
38+
import org.apache.commons.math3.linear.BlockRealMatrix;
3739
import org.apache.commons.math3.linear.EigenDecomposition;
3840
import org.apache.commons.math3.linear.RealMatrix;
3941

@@ -47,7 +49,7 @@ public class MeshStats
4749
* Computes the volume of the specified mesh.
4850
*
4951
* @return the volume in physical units.
50-
* @implNote op names='geom.size', label='Geometric (2D): Size',
52+
* @implNote op names='geom.size', label='Geometric (3D): Volume',
5153
* priority='9999.'
5254
*/
5355
public static double volume( final Mesh mesh )
@@ -84,6 +86,18 @@ public static double volume( final Mesh mesh )
8486
return Math.abs( sum );
8587
}
8688

89+
/**
90+
* Computes the volume of the convex hull of the specified mesh.
91+
*
92+
* @param mesh a {@link Mesh}
93+
* @return the volume in physical units.
94+
* @implNote op names='geom.sizeConvexHull', label='Geometric (3D): Convex Hull Volume',
95+
* priority='9999.'
96+
*/
97+
public static double convexHullVolume(final Mesh mesh) {
98+
return volume(ConvexHull.calculate(mesh));
99+
}
100+
87101
/**
88102
* Returns the surface area of a mesh.
89103
* <p>
@@ -113,6 +127,18 @@ public static double surfaceArea( final Mesh mesh )
113127
return total;
114128
}
115129

130+
/**
131+
* Computes the surface area of the convex hull of the specified mesh.
132+
*
133+
* @param mesh a {@link Mesh}
134+
* @return the surface area in physical units.
135+
* @implNote op names='geom.boundarySizeConvexHull', label='Geometric (3D): Convex Hull Surface Area',
136+
* priority='9999.'
137+
*/
138+
public static double convexHullSurfaceArea(final Mesh mesh) {
139+
return surfaceArea(ConvexHull.calculate(mesh));
140+
}
141+
116142
/**
117143
* Returns the solidity of a mesh.
118144
* <p>
@@ -256,7 +282,7 @@ public static double compactness( final Mesh mesh )
256282
* @param input
257283
* the input mesh.
258284
* @return the centroid of the mesh.
259-
* @implNote op names='geom.centroid', priority='10000.'
285+
* @implNote op names='geom.centerOfGravity', priority='10000.'
260286
*/
261287
public static RealPoint centroid( final Mesh input )
262288
{
@@ -314,6 +340,127 @@ public static RealPoint centroid( final Mesh input )
314340
return new RealPoint( m100 / v, m010 / v, m001 / v );
315341
}
316342

343+
/**
344+
* Describes the elogation of a {@link Mesh}. As elongation is a metric of a
345+
* two-dimensional object, this functionality describes elongation as a
346+
* {@link RealMatrix}, where each index {@code x,y} is the elongation
347+
* considering principal axes {@code x} and {@code y}.
348+
*
349+
* @param input a {@link Mesh}
350+
* @return the elongation of each subset of principal axes of {@code input}
351+
* @implNote op names='geom.elongation', label='Geometric (3D): Elongation', priority='10000.'
352+
*/
353+
public static RealMatrix elongation(final Mesh input) {
354+
final RealMatrix it = InertiaTensor.calculate(input);
355+
final EigenDecomposition ed = new EigenDecomposition(it);
356+
357+
final double l1 = ed.getRealEigenvalue(0) - ed.getRealEigenvalue(2) + ed
358+
.getRealEigenvalue(1);
359+
final double l2 = ed.getRealEigenvalue(0) - ed.getRealEigenvalue(1) + ed
360+
.getRealEigenvalue(2);
361+
final double l3 = ed.getRealEigenvalue(2) - ed.getRealEigenvalue(0) + ed
362+
.getRealEigenvalue(1);
363+
364+
final double g = 1 / (8 * Math.PI / 15);
365+
366+
final double a = Math.pow(g * l1 * l1 / Math.sqrt(l2 * l3), 1 / 5d);
367+
final double b = Math.pow(g * l2 * l2 / Math.sqrt(l1 * l3), 1 / 5d);
368+
final double c = Math.pow(g * l3 * l3 / Math.sqrt(l1 * l2), 1 / 5d);
369+
final BlockRealMatrix out = new BlockRealMatrix(3, 3);
370+
out.setRow(0, new double[] {elongation(a, a), elongation(a, b), elongation(a, c)});
371+
out.setRow(1, new double[] {elongation(b, a), elongation(b, b), elongation(b, c)});
372+
out.setRow(2, new double[] {elongation(c, a), elongation(c, b), elongation(c, c)});
373+
return out;
374+
}
375+
376+
private static double elongation(double major, double minor) {
377+
// Ensure elongation contained in [0, 1]
378+
if (minor > major) {
379+
double tmp = minor;
380+
minor = major;
381+
major = tmp;
382+
}
383+
return 1 - (minor / major);
384+
}
385+
386+
/**
387+
* Describes the elongation of the two <b>larger</b> principle axes of the
388+
* minimum box containing a {@link Mesh}. Provides functionality equivalent
389+
* to the {@code "geom.mainElongation"} Op of ImageJ Ops.
390+
*
391+
* @param input a {@link Mesh}
392+
* @return the elongation of a cross-section containing the two <b>larger</b> principle axes
393+
* @implNote op names='geom.mainElongation', label='Geometric (3D): Main Elongation', priority='10000.'
394+
*/
395+
public static double mainElongation(final Mesh input){
396+
return elongation(input).getEntry(0, 1);
397+
}
398+
399+
/**
400+
* Describes the elongation of the two <b>smaller</b> principle axes of the
401+
* minimum box containing a {@link Mesh}. Provides functionality equivalent
402+
* to the {@code "geom.medianElongation"} Op of ImageJ Ops.
403+
*
404+
* @param input a {@link Mesh}
405+
* @return the elongation of a cross-section containing the two <b>smaller</b> principle axes
406+
* @implNote op names='geom.medianElongation', label='Geometric (3D): Median Elongation', priority='10000.'
407+
*/
408+
public static double medianElongation(final Mesh input) {
409+
return elongation(input).getEntry(1, 2);
410+
}
411+
412+
/**
413+
* Describes the number of vertices on the surface of a {@link Mesh}.
414+
*
415+
* @param input a {@link Mesh}
416+
* @return the number of vertices in {@code input}
417+
* @implNote op names='geom.verticesCount', label='Geometric (3D): Surface Vertices Count', priority='10000.'
418+
*/
419+
public static long verticesCount(final Mesh input) {
420+
return input.vertices().size();
421+
}
422+
423+
/**
424+
* Describes the number of vertices on the surface of the convex hull of {@link Mesh}.
425+
*
426+
* @param input a {@link Mesh}
427+
* @return the number of vertices in the convex hull of {@code input}
428+
* @implNote op names='geom.verticesCountConvexHull', label='Geometric (3D): Convex Hull Vertices Count', priority='10000.'
429+
*/
430+
public static long convexHullVerticesCount(final Mesh input) {
431+
return ConvexHull.calculate(input).vertices().size();
432+
}
433+
434+
435+
/**
436+
* Describes the spareness of {@code geom.spareness}. Based on ImageJ.
437+
*
438+
* @author Tim-Oliver Buchholz (University of Konstanz)
439+
* @implNote op names='geom.spareness', label='Geometric (3D): Spareness',
440+
* priority='10000.'
441+
*/
442+
public static double spareness(final Mesh input) {
443+
final RealMatrix it = InertiaTensor.calculate(input);
444+
final EigenDecomposition ed = new EigenDecomposition(it);
445+
446+
final double l1 = ed.getRealEigenvalue(0) - ed.getRealEigenvalue(2) + ed
447+
.getRealEigenvalue(1);
448+
final double l2 = ed.getRealEigenvalue(0) - ed.getRealEigenvalue(1) + ed
449+
.getRealEigenvalue(2);
450+
final double l3 = ed.getRealEigenvalue(2) - ed.getRealEigenvalue(0) + ed
451+
.getRealEigenvalue(1);
452+
453+
final double g = 1 / (8 * Math.PI / 15);
454+
455+
final double a = Math.pow(g * l1 * l1 / Math.sqrt(l2 * l3), 1 / 5d);
456+
final double b = Math.pow(g * l2 * l2 / Math.sqrt(l1 * l3), 1 / 5d);
457+
final double c = Math.pow(g * l3 * l3 / Math.sqrt(l1 * l2), 1 / 5d);
458+
459+
double volumeEllipsoid = (4 / 3d * Math.PI * a * b * c);
460+
461+
return volume(input) / volumeEllipsoid;
462+
}
463+
317464
private MeshStats()
318465
{}
319466
}

src/main/java/net/imglib2/mesh/alg/MarchingCubesBooleanType.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ private static byte ubyte( final int unsignedByte )
104104
return ( byte ) ( unsignedByte & 0xff );
105105
}
106106

107+
/**
108+
* Generates a {@link Mesh} surface from a {@link RandomAccessibleInterval}, containing all points with data value {@code true}
109+
*
110+
* @param input the input {@link RandomAccessibleInterval}
111+
* @return a {@link Mesh} describing a surface within {@code input} of all {@code true} points.
112+
* @param <T> the element type of {@code input}
113+
* @implNote op names="geom.marchingCubes", priority="100."
114+
*/
107115
public static < T extends BooleanType< T > > Mesh calculate( final RandomAccessibleInterval< T > input )
108116
{
109117
final double[][] vertlist = new double[ 12 ][];

src/main/java/net/imglib2/mesh/alg/MarchingCubesRealType.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
*
4848
* @author Tim-Oliver Buchholz (University of Konstanz)
4949
* @author Tobias Pietzsch
50+
*
5051
*/
5152
public class MarchingCubesRealType
5253
{
@@ -106,6 +107,15 @@ private static byte ubyte( final int unsignedByte )
106107
return ( byte ) ( unsignedByte & 0xff );
107108
}
108109

110+
/**
111+
* Generates a {@link Mesh} surface from a {@link RandomAccessibleInterval}, containing all points with data value {@code isolevel}
112+
*
113+
* @param input the input {@link RandomAccessibleInterval}
114+
* @param isoLevel the value such that all locations on the output surface
115+
* @return a {@link Mesh} containing the isosurface within {@code input} corresponding to {@code isolevel}
116+
* @param <T> the element type of {@code input}
117+
* @implNote op names="geom.marchingCubes"
118+
*/
109119
public static < T extends RealType< T > > Mesh calculate( final RandomAccessibleInterval< T > input, final double isoLevel )
110120
{
111121
final double[][] vertlist = new double[ 12 ][ 3 ];

0 commit comments

Comments
 (0)