Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support 3D segmentation with TrackMate-Weka. #2

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
674 changes: 0 additions & 674 deletions LICENSE

This file was deleted.

4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.scijava</groupId>
<artifactId>pom-scijava</artifactId>
<version>34.0.0</version>
<version>37.0.0</version>
<relativePath />
</parent>

Expand Down Expand Up @@ -86,7 +86,7 @@

<javaGeom.version>0.11.1</javaGeom.version>

<TrackMate.version>7.10.2</TrackMate.version>
<TrackMate.version>8.0.0-SNAPSHOT</TrackMate.version>
</properties>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
package fiji.plugin.trackmate.weka;

import static fiji.plugin.trackmate.detection.DetectorKeys.KEY_TARGET_CHANNEL;
import static fiji.plugin.trackmate.detection.ThresholdDetectorFactory.KEY_SMOOTHING_SCALE;
import static fiji.plugin.trackmate.weka.WekaDetectorFactory.KEY_CLASSIFIER_FILEPATH;
import static fiji.plugin.trackmate.weka.WekaDetectorFactory.KEY_CLASS_INDEX;
import static fiji.plugin.trackmate.weka.WekaDetectorFactory.KEY_PROBA_THRESHOLD;
Expand Down Expand Up @@ -108,13 +109,16 @@ protected Pair< Model, Double > runPreviewDetection(
*/

final Map< String, Object > dsettings = new HashMap<>( detectorSettings );
@SuppressWarnings( "unchecked" )
final ImgPlus< T > img = TMUtils.rawWraps( settings.imp );
final int channel = ( Integer ) dsettings.get( KEY_TARGET_CHANNEL ) - 1;
final ImgPlus< T > input = TMUtils.hyperSlice( img, channel, frame );
final int classIndex = ( Integer ) dsettings.get( KEY_CLASS_INDEX );
final double probaThreshold = ( Double ) dsettings.get( KEY_PROBA_THRESHOLD );
final boolean simplify = true;
final Object smoothingObj = dsettings.get( KEY_SMOOTHING_SCALE );
final double smoothingScale = smoothingObj == null
? -1.
: ( ( Number ) smoothingObj ).doubleValue();

final boolean is3D = input.dimensionIndex( Axes.Z ) >= 0;
// First test to make sure we can read the classifier file.
Expand Down Expand Up @@ -180,7 +184,7 @@ protected Pair< Model, Double > runPreviewDetection(
}

logger.log( "Creating spots from probabilities." );
final List< Spot > spots = wekaRunner.getSpotsFromLastProbabilities( probaThreshold, simplify );
final List< Spot > spots = wekaRunner.getSpotsFromLastProbabilities( probaThreshold, simplify, smoothingScale );
if ( spots == null )
{
logger.error( "Problem creating spots: " + wekaRunner.getErrorMessage() );
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/fiji/plugin/trackmate/weka/WekaDetector.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,24 @@ public class WekaDetector< T extends RealType< T > & NativeType< T > > implement

private final boolean simplify;

private final double smoothingScale;

public WekaDetector(
final WekaRunner< T > runner,
final ImgPlus< T > img,
final Interval interval,
final int classIndex,
final double probaThreshold,
final boolean simplify )
final boolean simplify,
final double smoothingScale )
{
this.runner = runner;
this.img = img;
this.interval = DetectionUtils.squeeze( interval );
this.classIndex = classIndex;
this.probaThreshold = probaThreshold;
this.simplify = simplify;
this.smoothingScale = smoothingScale;
this.baseErrorMessage = BASE_ERROR_MESSAGE;
}

Expand All @@ -99,7 +103,7 @@ public boolean process()
return false;
}

spots = runner.getSpots( probabilities, TMUtils.getSpatialCalibration( img ), probaThreshold, simplify );
spots = runner.getSpots( probabilities, TMUtils.getSpatialCalibration( img ), probaThreshold, simplify, smoothingScale );
if ( spots == null )
{
System.err.println( "Problem creating spots: " + runner.getErrorMessage() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
package fiji.plugin.trackmate.weka;

import static fiji.plugin.trackmate.detection.DetectorKeys.KEY_TARGET_CHANNEL;
import static fiji.plugin.trackmate.detection.ThresholdDetectorFactory.KEY_SMOOTHING_SCALE;
import static fiji.plugin.trackmate.gui.Fonts.BIG_FONT;
import static fiji.plugin.trackmate.gui.Fonts.FONT;
import static fiji.plugin.trackmate.gui.Fonts.SMALL_FONT;
Expand All @@ -30,15 +31,12 @@
import static fiji.plugin.trackmate.weka.WekaDetectorFactory.KEY_CLASS_INDEX;
import static fiji.plugin.trackmate.weka.WekaDetectorFactory.KEY_PROBA_THRESHOLD;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
Expand All @@ -49,7 +47,6 @@
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.JTextField;
Expand All @@ -64,6 +61,8 @@
import fiji.plugin.trackmate.Settings;
import fiji.plugin.trackmate.gui.GuiUtils;
import fiji.plugin.trackmate.gui.components.ConfigurationPanel;
import fiji.plugin.trackmate.gui.components.PanelProbaThreshold;
import fiji.plugin.trackmate.gui.components.PanelSmoothContour;
import fiji.plugin.trackmate.util.EverythingDisablerAndReenabler;
import fiji.plugin.trackmate.util.FileChooser;
import fiji.plugin.trackmate.util.FileChooser.DialogType;
Expand All @@ -78,8 +77,6 @@ public class WekaDetectorConfigurationPanel extends ConfigurationPanel

private static final long serialVersionUID = 1L;

private static final NumberFormat THRESHOLD_FORMAT = new DecimalFormat( "#.##" );

protected static final ImageIcon ICON = new ImageIcon( getResource( "images/TrackMateWeka-logo-100px.png" ) );

private static final String TITLE = WekaDetectorFactory.NAME;
Expand All @@ -94,14 +91,16 @@ public class WekaDetectorConfigurationPanel extends ConfigurationPanel

private final JButton btnBrowse;

private final JFormattedTextField ftfProbaThreshold;

protected final PrefService prefService;

private final WekaDetectionPreviewer< ? > previewer;

private final boolean is3D;

private final PanelSmoothContour smoothingPanel;

private final PanelProbaThreshold probaThresholdPanel;

/**
* Create the panel.
*/
Expand Down Expand Up @@ -238,25 +237,29 @@ public WekaDetectorConfigurationPanel( final Settings settings, final Model mode
* Proba threshold.
*/

final JLabel lblScoreTreshold = new JLabel( "Threshold on probability:" );
lblScoreTreshold.setFont( SMALL_FONT );
final GridBagConstraints gbcLblScoreTreshold = new GridBagConstraints();
gbcLblScoreTreshold.anchor = GridBagConstraints.EAST;
gbcLblScoreTreshold.insets = new Insets( 5, 5, 5, 5 );
gbcLblScoreTreshold.gridx = 0;
gbcLblScoreTreshold.gridy = 6;
add( lblScoreTreshold, gbcLblScoreTreshold );

ftfProbaThreshold = new JFormattedTextField( THRESHOLD_FORMAT );
ftfProbaThreshold.setFont( SMALL_FONT );
ftfProbaThreshold.setMinimumSize( new Dimension( 60, 20 ) );
ftfProbaThreshold.setHorizontalAlignment( SwingConstants.CENTER );
probaThresholdPanel = new PanelProbaThreshold( 0.5 );
final GridBagConstraints gbcScore = new GridBagConstraints();
gbcScore.fill = GridBagConstraints.HORIZONTAL;
gbcScore.anchor = GridBagConstraints.NORTHWEST;
gbcScore.insets = new Insets( 5, 5, 5, 5 );
gbcScore.gridx = 1;
gbcScore.gridx = 0;
gbcScore.gridy = 6;
add( ftfProbaThreshold, gbcScore );
gbcScore.gridwidth = 3;
add( probaThresholdPanel, gbcScore );

/*
* Smooth output.
*/

smoothingPanel = new PanelSmoothContour( -1., model.getSpaceUnits() );
final GridBagConstraints gbSmoothPanel = new GridBagConstraints();
gbSmoothPanel.anchor = GridBagConstraints.NORTHWEST;
gbSmoothPanel.insets = new Insets( 5, 5, 5, 5 );
gbSmoothPanel.gridwidth = 3;
gbSmoothPanel.gridx = 0;
gbSmoothPanel.gridy = 7;
gbSmoothPanel.fill = GridBagConstraints.HORIZONTAL;
this.add( smoothingPanel, gbSmoothPanel );

/*
* Refresh class names.
Expand All @@ -269,7 +272,7 @@ public WekaDetectorConfigurationPanel( final Settings settings, final Model mode
gbcBtnClassNames.anchor = GridBagConstraints.SOUTHWEST;
gbcBtnClassNames.insets = new Insets( 5, 5, 5, 5 );
gbcBtnClassNames.gridx = 0;
gbcBtnClassNames.gridy = 7;
gbcBtnClassNames.gridy = 8;
add( btnClassNames, gbcBtnClassNames );

/*
Expand All @@ -283,7 +286,7 @@ public WekaDetectorConfigurationPanel( final Settings settings, final Model mode
gbcBtnLastProba.anchor = GridBagConstraints.SOUTHEAST;
gbcBtnLastProba.insets = new Insets( 5, 5, 5, 5 );
gbcBtnLastProba.gridx = 1;
gbcBtnLastProba.gridy = 7;
gbcBtnLastProba.gridy = 8;
add( btnLastProba, gbcBtnLastProba );

/*
Expand All @@ -295,7 +298,7 @@ public WekaDetectorConfigurationPanel( final Settings settings, final Model mode
gbcBtnPreview.fill = GridBagConstraints.BOTH;
gbcBtnPreview.insets = new Insets( 5, 5, 5, 5 );
gbcBtnPreview.gridx = 0;
gbcBtnPreview.gridy = 8;
gbcBtnPreview.gridy = 9;

previewer = new WekaDetectionPreviewer<>(
model,
Expand Down Expand Up @@ -355,8 +358,11 @@ public Map< String, Object > getSettings()
final int classID = cmbboxClassId.getSelectedIndex();
settings.put( KEY_CLASS_INDEX, classID );

final double probaThreshold = ( ( Number ) ftfProbaThreshold.getValue() ).doubleValue();
final double probaThreshold = probaThresholdPanel.getThreshold();
settings.put( KEY_PROBA_THRESHOLD, probaThreshold );

final double scale = smoothingPanel.getScale();
settings.put( KEY_SMOOTHING_SCALE, scale );
return settings;
}

Expand All @@ -369,7 +375,14 @@ public void setSettings( final Map< String, Object > settings )
modelFileTextField.setText( filePath );
cmbboxClassId.setSelectedIndex( ( Integer ) settings.get( KEY_CLASS_INDEX ) );
sliderChannel.setValue( ( Integer ) settings.get( KEY_TARGET_CHANNEL ) );
ftfProbaThreshold.setValue( settings.get( KEY_PROBA_THRESHOLD ) );

final Object thresholdObj = settings.get( KEY_PROBA_THRESHOLD );
final double threshold = thresholdObj == null ? -1. : ( ( Number ) thresholdObj ).doubleValue();
probaThresholdPanel.setThreshold( threshold );

final Object scaleObj = settings.get( KEY_SMOOTHING_SCALE );
final double scale = scaleObj == null ? -1. : ( ( Number ) scaleObj ).doubleValue();
smoothingPanel.setScale( scale );
}

@Override
Expand Down
27 changes: 21 additions & 6 deletions src/main/java/fiji/plugin/trackmate/weka/WekaDetectorFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
Expand All @@ -23,12 +23,14 @@

import static fiji.plugin.trackmate.detection.DetectorKeys.DEFAULT_TARGET_CHANNEL;
import static fiji.plugin.trackmate.detection.DetectorKeys.KEY_TARGET_CHANNEL;
import static fiji.plugin.trackmate.detection.ThresholdDetectorFactory.KEY_SMOOTHING_SCALE;
import static fiji.plugin.trackmate.io.IOUtils.readDoubleAttribute;
import static fiji.plugin.trackmate.io.IOUtils.readIntegerAttribute;
import static fiji.plugin.trackmate.io.IOUtils.readStringAttribute;
import static fiji.plugin.trackmate.io.IOUtils.writeAttribute;
import static fiji.plugin.trackmate.io.IOUtils.writeTargetChannel;
import static fiji.plugin.trackmate.util.TMUtils.checkMapKeys;
import static fiji.plugin.trackmate.util.TMUtils.checkOptionalParameter;
import static fiji.plugin.trackmate.util.TMUtils.checkParameter;

import java.util.ArrayList;
Expand All @@ -39,6 +41,7 @@
import javax.swing.ImageIcon;

import org.jdom2.Element;
import org.scijava.Priority;
import org.scijava.plugin.Plugin;

import fiji.plugin.trackmate.Model;
Expand All @@ -54,7 +57,7 @@
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.RealType;

@Plugin( type = SpotDetectorFactory.class )
@Plugin( type = SpotDetectorFactory.class, priority = Priority.LOW - 4.1 )
public class WekaDetectorFactory< T extends RealType< T > & NativeType< T > > implements SpotDetectorFactory< T >
{

Expand Down Expand Up @@ -92,7 +95,8 @@ public class WekaDetectorFactory< T extends RealType< T > & NativeType< T > > im
public static final String INFO_TEXT = "<html>"
+ "This detector relies on the 'Trainable Weka segmentation' plugin to detect objects."
+ "<p>"
+ "It works for 2D and 3D images, but returns contours only for 2D images."
+ "It works for 2D and 3D images, returns contours for 2D images and meshes"
+ "for 3D images."
+ "<p>"
+ "You need to provide the path to a classifier previously trained and saved using the "
+ "'Trainable Weka segmentation' plugin. It will classically be a '.model' file. "
Expand Down Expand Up @@ -132,13 +136,18 @@ public SpotDetector< T > getDetector( final Interval interval, final int frame )
final int classIndex = ( Integer ) settings.get( KEY_CLASS_INDEX );
final double probaThreshold = ( Double ) settings.get( KEY_PROBA_THRESHOLD );
final boolean simplify = true;
final Object smoothingObj = settings.get( KEY_SMOOTHING_SCALE );
final double smoothingScale = smoothingObj == null
? -1.
: ( ( Number ) smoothingObj ).doubleValue();
final WekaDetector< T > detector = new WekaDetector<>(
runner,
input,
interval,
classIndex,
probaThreshold,
simplify );
simplify,
smoothingScale );
return detector;
}

Expand Down Expand Up @@ -197,6 +206,7 @@ public boolean marshall( final Map< String, Object > settings, final Element ele
ok = ok && writeAttribute( settings, element, KEY_CLASSIFIER_FILEPATH, String.class, errorHolder );
ok = ok && writeAttribute( settings, element, KEY_CLASS_INDEX, Integer.class, errorHolder );
ok = ok && writeAttribute( settings, element, KEY_PROBA_THRESHOLD, Double.class, errorHolder );
ok = ok && writeAttribute( settings, element, KEY_SMOOTHING_SCALE, Double.class, errorHolder );

if ( !ok )
errorMessage = errorHolder.toString();
Expand All @@ -214,6 +224,7 @@ public boolean unmarshall( final Element element, final Map< String, Object > se
ok = ok && readStringAttribute( element, settings, KEY_CLASSIFIER_FILEPATH, errorHolder );
ok = ok && readIntegerAttribute( element, settings, KEY_CLASS_INDEX, errorHolder );
ok = ok && readDoubleAttribute( element, settings, KEY_PROBA_THRESHOLD, errorHolder );
ok = ok & readDoubleAttribute( element, settings, KEY_SMOOTHING_SCALE, errorHolder );

if ( !ok )
{
Expand All @@ -237,6 +248,7 @@ public Map< String, Object > getDefaultSettings()
settings.put( KEY_CLASS_INDEX, DEFAULT_CLASS_INDEX );
settings.put( KEY_PROBA_THRESHOLD, DEFAULT_PROBA_THRESHOLD );
settings.put( KEY_CLASSIFIER_FILEPATH, null );
settings.put( KEY_SMOOTHING_SCALE, -1. );
return settings;
}

Expand All @@ -249,12 +261,15 @@ public boolean checkSettings( final Map< String, Object > settings )
ok = ok & checkParameter( settings, KEY_CLASS_INDEX, Integer.class, errorHolder );
ok = ok & checkParameter( settings, KEY_PROBA_THRESHOLD, Double.class, errorHolder );
ok = ok & checkParameter( settings, KEY_CLASSIFIER_FILEPATH, String.class, errorHolder );
ok = ok & checkOptionalParameter( settings, KEY_SMOOTHING_SCALE, Double.class, errorHolder );
final List< String > mandatoryKeys = new ArrayList<>();
mandatoryKeys.add( KEY_TARGET_CHANNEL );
mandatoryKeys.add( KEY_CLASS_INDEX );
mandatoryKeys.add( KEY_PROBA_THRESHOLD );
mandatoryKeys.add( KEY_CLASSIFIER_FILEPATH );
ok = ok & checkMapKeys( settings, mandatoryKeys, null, errorHolder );
final List< String > optionalKeys = new ArrayList<>();
optionalKeys.add( KEY_SMOOTHING_SCALE );
ok = ok & checkMapKeys( settings, mandatoryKeys, optionalKeys, errorHolder );
if ( !ok )
errorMessage = errorHolder.toString();

Expand Down
Loading
Loading