-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
An action to smooth meshes with Tuabin smoothing.
- Loading branch information
Showing
4 changed files
with
447 additions
and
0 deletions.
There are no files selected for viewing
77 changes: 77 additions & 0 deletions
77
src/main/java/fiji/plugin/trackmate/action/meshtools/MeshSmoother.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package fiji.plugin.trackmate.action.meshtools; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import fiji.plugin.trackmate.Logger; | ||
import fiji.plugin.trackmate.Spot; | ||
import fiji.plugin.trackmate.SpotMesh; | ||
import net.imglib2.mesh.Mesh; | ||
import net.imglib2.mesh.Meshes; | ||
import net.imglib2.mesh.alg.TaubinSmoothing; | ||
import net.imglib2.mesh.alg.TaubinSmoothing.TaubinWeightType; | ||
import net.imglib2.mesh.impl.nio.BufferMesh; | ||
|
||
public class MeshSmoother | ||
{ | ||
|
||
private final Map< SpotMesh, BufferMesh > undoMap; | ||
|
||
private final Logger logger; | ||
|
||
public MeshSmoother( final Iterable< Spot > spots, final Logger logger ) | ||
{ | ||
this.logger = logger; | ||
// Store undo. | ||
this.undoMap = new HashMap<>(); | ||
final double[] center = new double[ 3 ]; | ||
for ( final Spot spot : spots ) | ||
{ | ||
if ( SpotMesh.class.isInstance( spot ) ) | ||
{ | ||
final SpotMesh sm = ( SpotMesh ) spot; | ||
final Mesh mesh = sm.getMesh(); | ||
final BufferMesh meshCopy = new BufferMesh( mesh.vertices().size(), mesh.triangles().size() ); | ||
Meshes.copy( mesh, meshCopy ); | ||
sm.localize( center ); | ||
Meshes.translate( meshCopy, center ); | ||
undoMap.put( sm, meshCopy ); | ||
} | ||
} | ||
} | ||
|
||
public void undo() | ||
{ | ||
logger.setStatus( "Undoing mesh smoothing" ); | ||
final Set< SpotMesh > keys = undoMap.keySet(); | ||
final int nSpots = keys.size(); | ||
int i = 0; | ||
for ( final SpotMesh sm : keys ) | ||
{ | ||
final BufferMesh old = undoMap.get( sm ); | ||
sm.setMesh( old ); | ||
logger.setProgress( ( double ) ( ++i ) / nSpots ); | ||
} | ||
logger.setStatus( "" ); | ||
} | ||
|
||
public void smooth( final int nIters, final double mu, final double lambda, final TaubinWeightType weightType ) | ||
{ | ||
logger.setStatus( "Taubin smoothing" ); | ||
final Set< SpotMesh > keys = undoMap.keySet(); | ||
final int nSpots = keys.size(); | ||
int i = 0; | ||
final double[] center = new double[ 3 ]; | ||
for ( final SpotMesh sm : keys ) | ||
{ | ||
final Mesh mesh = sm.getMesh(); | ||
sm.localize( center ); | ||
Meshes.translate( mesh, center ); | ||
final BufferMesh smoothedMesh = TaubinSmoothing.smooth( mesh, nIters, lambda, mu, weightType ); | ||
sm.setMesh( smoothedMesh ); | ||
logger.setProgress( ( double ) ( ++i ) / nSpots ); | ||
} | ||
logger.setStatus( "" ); | ||
} | ||
} |
117 changes: 117 additions & 0 deletions
117
src/main/java/fiji/plugin/trackmate/action/meshtools/MeshSmootherAction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package fiji.plugin.trackmate.action.meshtools; | ||
|
||
import java.awt.Frame; | ||
|
||
import javax.swing.ImageIcon; | ||
import javax.swing.JFrame; | ||
import javax.swing.JLabel; | ||
|
||
import org.scijava.plugin.Plugin; | ||
|
||
import fiji.plugin.trackmate.ModelChangeEvent; | ||
import fiji.plugin.trackmate.SelectionModel; | ||
import fiji.plugin.trackmate.TrackMate; | ||
import fiji.plugin.trackmate.action.AbstractTMAction; | ||
import fiji.plugin.trackmate.action.TrackMateAction; | ||
import fiji.plugin.trackmate.action.TrackMateActionFactory; | ||
import fiji.plugin.trackmate.gui.GuiUtils; | ||
import fiji.plugin.trackmate.gui.Icons; | ||
import fiji.plugin.trackmate.gui.displaysettings.DisplaySettings; | ||
import fiji.plugin.trackmate.util.EverythingDisablerAndReenabler; | ||
|
||
public class MeshSmootherAction extends AbstractTMAction | ||
{ | ||
|
||
@Override | ||
public void execute( final TrackMate trackmate, final SelectionModel selectionModel, final DisplaySettings displaySettings, final Frame parent ) | ||
{ | ||
final MeshSmoother smoother = new MeshSmoother( trackmate.getModel().getSpots().iterable( true ), logger ); | ||
|
||
final MeshSmootherModel model = new MeshSmootherModel(); | ||
final MeshSmootherPanel panel = new MeshSmootherPanel( model ); | ||
|
||
panel.btnRun.addActionListener( e -> { | ||
new Thread( () -> { | ||
final EverythingDisablerAndReenabler enabler = new EverythingDisablerAndReenabler( panel, new Class[] { JLabel.class } ); | ||
try | ||
{ | ||
enabler.disable(); | ||
smoother.smooth( model.getNIters(), model.getMu(), model.getLambda(), model.getWeightType() ); | ||
// Trigger refresh. | ||
trackmate.getModel().getModelChangeListener().forEach( l -> l.modelChanged( new ModelChangeEvent( this, ModelChangeEvent.SPOTS_COMPUTED ) ) ); | ||
} | ||
finally | ||
{ | ||
enabler.reenable(); | ||
} | ||
}, "TrackMate mesh smoother" ).start(); | ||
} ); | ||
|
||
panel.btnUndo.addActionListener( e -> { | ||
new Thread( () -> { | ||
final EverythingDisablerAndReenabler enabler = new EverythingDisablerAndReenabler( panel, new Class[] { JLabel.class } ); | ||
try | ||
{ | ||
enabler.disable(); | ||
smoother.undo(); | ||
// Trigger refresh. | ||
trackmate.getModel().getModelChangeListener().forEach( l -> l.modelChanged( new ModelChangeEvent( this, ModelChangeEvent.SPOTS_COMPUTED ) ) ); | ||
} | ||
finally | ||
{ | ||
enabler.reenable(); | ||
} | ||
}, "TrackMate mesh smoother" ).start(); | ||
} ); | ||
|
||
final JFrame frame = new JFrame( "Smoothing params" ); | ||
frame.getContentPane().add( panel ); | ||
frame.setSize( 400, 300 ); | ||
GuiUtils.positionWindow( frame, parent ); | ||
frame.setVisible( true ); | ||
} | ||
|
||
@Plugin( type = TrackMateActionFactory.class ) | ||
public static class Factory implements TrackMateActionFactory | ||
{ | ||
|
||
public static final String NAME = "Smooth 3D meshes"; | ||
|
||
public static final String KEY = "MESH_SMOOTHER"; | ||
|
||
public static final String INFO_TEXT = "<html>" | ||
+ "Displays a tool to smooth the 3D mesh present in " | ||
+ "the data, using the Taubin smoothing algorithm.</html>"; | ||
|
||
@Override | ||
public String getInfoText() | ||
{ | ||
return INFO_TEXT; | ||
} | ||
|
||
@Override | ||
public String getKey() | ||
{ | ||
return KEY; | ||
} | ||
|
||
@Override | ||
public TrackMateAction create() | ||
{ | ||
return new MeshSmootherAction(); | ||
} | ||
|
||
@Override | ||
public ImageIcon getIcon() | ||
{ | ||
return Icons.VECTOR_ICON; | ||
} | ||
|
||
@Override | ||
public String getName() | ||
{ | ||
return NAME; | ||
} | ||
} | ||
|
||
} |
68 changes: 68 additions & 0 deletions
68
src/main/java/fiji/plugin/trackmate/action/meshtools/MeshSmootherModel.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package fiji.plugin.trackmate.action.meshtools; | ||
|
||
import net.imglib2.mesh.alg.TaubinSmoothing.TaubinWeightType; | ||
|
||
public class MeshSmootherModel | ||
{ | ||
|
||
private int nIters = 10; | ||
|
||
private double mu = 0.5; | ||
|
||
private double lambda = -0.53; | ||
|
||
private TaubinWeightType weightType = TaubinWeightType.NAIVE; | ||
|
||
public void setWeightType( final TaubinWeightType weightType ) | ||
{ | ||
this.weightType = weightType; | ||
} | ||
|
||
public void setMu( final double mu ) | ||
{ | ||
this.mu = Math.min( 1., Math.max( 0, mu ) ); | ||
} | ||
|
||
public void setLambda( final double lambda ) | ||
{ | ||
this.lambda = Math.min( 0., Math.max( -1., lambda ) ); | ||
} | ||
|
||
public void setNIters( final int nIters ) | ||
{ | ||
this.nIters = Math.max( 0, nIters ); | ||
} | ||
|
||
public double getMu() | ||
{ | ||
return mu; | ||
} | ||
|
||
public double getLambda() | ||
{ | ||
return lambda; | ||
} | ||
|
||
public int getNIters() | ||
{ | ||
return nIters; | ||
} | ||
|
||
public TaubinWeightType getWeightType() | ||
{ | ||
return weightType; | ||
} | ||
|
||
/** | ||
* Ad-hoc method setting parameters for little smoothing (close to 0) or a | ||
* lot of smoothing (close to 1). | ||
* | ||
* @param smoothing | ||
* the smoothing parameter. | ||
*/ | ||
public void setSmoothing( final double smoothing ) | ||
{ | ||
setMu( Math.max( 0, Math.min( 0.97, smoothing ) ) ); | ||
setLambda( -mu - 0.03 ); | ||
} | ||
} |
Oops, something went wrong.