Skip to content

Commit

Permalink
Add commonly useful lazy features.
Browse files Browse the repository at this point in the history
- Number of incoming and outgoing links on a spot.
Useful to fish for cells that have a division or a merge, and debug
unwanted linking events.
- Oriented time-difference for links.
Useful to detect buggy links introduced by improper semi-auto tracking.
Debugging without this feature is really a pain.
  • Loading branch information
tinevez committed Oct 22, 2023
1 parent 1b6f47a commit f8368f4
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 13 deletions.
142 changes: 142 additions & 0 deletions src/main/java/org/mastodon/mamut/feature/LinkDeltaFrameFeature.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*-
* #%L
* Mastodon
* %%
* Copyright (C) 2014 - 2023 Tobias Pietzsch, Jean-Yves Tinevez
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.mastodon.mamut.feature;

import static org.mastodon.feature.FeatureProjectionKey.key;

import java.util.Collections;
import java.util.Set;

import org.mastodon.feature.Dimension;
import org.mastodon.feature.Feature;
import org.mastodon.feature.FeatureProjection;
import org.mastodon.feature.FeatureProjectionKey;
import org.mastodon.feature.FeatureProjectionSpec;
import org.mastodon.feature.FeatureSpec;
import org.mastodon.feature.Multiplicity;
import org.mastodon.mamut.model.Link;
import org.mastodon.mamut.model.ModelGraph;
import org.mastodon.mamut.model.Spot;
import org.scijava.plugin.Plugin;

public class LinkDeltaFrameFeature implements Feature< Link >
{

private static final String KEY = "Link delta T";

private static final String HELP_STRING = "The time difference in number of time-points between the target and source of links.";

private static final FeatureProjectionSpec PROJECTION_SPEC = new FeatureProjectionSpec( KEY, Dimension.NONE );

public static final Spec SPEC = new Spec();

final ModelGraph graph;

@Plugin( type = FeatureSpec.class )
public static class Spec extends FeatureSpec< LinkDeltaFrameFeature, Link >
{
public Spec()
{
super(
KEY,
HELP_STRING,
LinkDeltaFrameFeature.class,
Link.class,
Multiplicity.SINGLE,
PROJECTION_SPEC );
}
}

public LinkDeltaFrameFeature( final ModelGraph graph )
{
this.graph = graph;
}

@Override
public FeatureProjection< Link > project( final FeatureProjectionKey key )
{
return key( PROJECTION_SPEC ).equals( key ) ? new MyProjection( graph ) : null;
}

@Override
public Set< FeatureProjection< Link > > projections()
{
return Collections.singleton( new MyProjection( graph ) );
}

@Override
public Spec getSpec()
{
return SPEC;
}

@Override
public void invalidate( final Link link )
{}

private static final class MyProjection implements FeatureProjection< Link >
{

private final Spot ref1;

private final Spot ref2;

public MyProjection( final ModelGraph graph )
{
this.ref1 = graph.vertexRef();
this.ref2 = graph.vertexRef();
}

@Override
public FeatureProjectionKey getKey()
{
return key( PROJECTION_SPEC );
}

@Override
public boolean isSet( final Link link )
{
return true;
}

@Override
public synchronized double value( final Link link )
{
final Spot source = link.getSource( ref1 );
final Spot target = link.getTarget( ref2 );
return target.getTimepoint() - source.getTimepoint();
}

@Override
public String units()
{
return Dimension.NONE_UNITS;
}
}
}
96 changes: 87 additions & 9 deletions src/main/java/org/mastodon/mamut/feature/SpotNLinksFeature.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
*/
package org.mastodon.mamut.feature;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.mastodon.feature.Dimension;
Expand All @@ -47,13 +49,21 @@ public class SpotNLinksFeature implements Feature< Spot >

public static final String KEY = "Spot N links";

private static final String HELP_STRING = "Computes the number of links that touch a spot.";
private static final String HELP_STRING = "Number of outgoing and incoming links of a spot.";

public static final FeatureProjectionSpec PROJECTION_SPEC = new FeatureProjectionSpec( KEY );
public static final FeatureProjectionSpec N_LINKS_PROJECTION_SPEC = new FeatureProjectionSpec( KEY );

public static final FeatureProjectionSpec N_OUTGOING_LINKS_PROJECTION_SPEC = new FeatureProjectionSpec( "N outgoing links" );

public static final FeatureProjectionSpec N_INCOMING_LINKS_PROJECTION_SPEC = new FeatureProjectionSpec( "N incoming links" );

public static final Spec SPEC = new Spec();

private final IntFeatureProjection< Spot > projection;
private final IntFeatureProjection< Spot > nLinksProjection;

private final IntFeatureProjection< Spot > nIncomingLinksProjection;

private final IntFeatureProjection< Spot > nOutgoingLinksProjection;

@Plugin( type = FeatureSpec.class )
public static class Spec extends FeatureSpec< SpotNLinksFeature, Spot >
Expand All @@ -66,25 +76,37 @@ public Spec()
SpotNLinksFeature.class,
Spot.class,
Multiplicity.SINGLE,
PROJECTION_SPEC );
N_LINKS_PROJECTION_SPEC,
N_OUTGOING_LINKS_PROJECTION_SPEC,
N_INCOMING_LINKS_PROJECTION_SPEC );
}
}

public SpotNLinksFeature()
{
this.projection = new MyProjection();
this.nLinksProjection = new NLinkProjection();
this.nOutgoingLinksProjection = new NOutgoingLinkProjection();
this.nIncomingLinksProjection = new NIncomingLinkProjection();
}

@Override
public FeatureProjection< Spot > project( final FeatureProjectionKey key )
{
return projection.getKey().equals( key ) ? projection : null;
if ( nLinksProjection.getKey().equals( key ) )
return nLinksProjection;
else if ( nOutgoingLinksProjection.getKey().equals( key ) )
return nOutgoingLinksProjection;
else if ( nIncomingLinksProjection.getKey().equals( key ) )
return nIncomingLinksProjection;
else
return null;
}

@Override
public Set< FeatureProjection< Spot > > projections()
{
return Collections.singleton( projection );
return Collections.unmodifiableSet( new HashSet<>( Arrays.asList(
nLinksProjection, nOutgoingLinksProjection, nIncomingLinksProjection ) ) );
}

@Override
Expand All @@ -97,13 +119,13 @@ public Spec getSpec()
public void invalidate( final Spot spot )
{}

private static final class MyProjection implements IntFeatureProjection< Spot >
private static final class NLinkProjection implements IntFeatureProjection< Spot >
{

@Override
public FeatureProjectionKey getKey()
{
return FeatureProjectionKey.key( PROJECTION_SPEC );
return FeatureProjectionKey.key( N_LINKS_PROJECTION_SPEC );
}

@Override
Expand All @@ -125,4 +147,60 @@ public String units()
}

}

private static final class NOutgoingLinkProjection implements IntFeatureProjection< Spot >
{

@Override
public FeatureProjectionKey getKey()
{
return FeatureProjectionKey.key( N_OUTGOING_LINKS_PROJECTION_SPEC );
}

@Override
public boolean isSet( final Spot obj )
{
return true;
}

@Override
public double value( final Spot obj )
{
return obj.outgoingEdges().size();
}

@Override
public String units()
{
return Dimension.NONE_UNITS;
}
}

private static final class NIncomingLinkProjection implements IntFeatureProjection< Spot >
{

@Override
public FeatureProjectionKey getKey()
{
return FeatureProjectionKey.key( N_INCOMING_LINKS_PROJECTION_SPEC );
}

@Override
public boolean isSet( final Spot obj )
{
return true;
}

@Override
public double value( final Spot obj )
{
return obj.incomingEdges().size();
}

@Override
public String units()
{
return Dimension.NONE_UNITS;
}
}
}
8 changes: 4 additions & 4 deletions src/main/java/org/mastodon/mamut/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.mastodon.graph.io.RawGraphIO.FileIdToGraphMap;
import org.mastodon.graph.io.RawGraphIO.GraphToFileIdMap;
import org.mastodon.labels.LabelSets;
import org.mastodon.mamut.feature.LinkDeltaFrameFeature;
import org.mastodon.mamut.feature.LinkDisplacementFeature;
import org.mastodon.mamut.feature.LinkTargetIdFeature;
import org.mastodon.mamut.feature.LinkVelocityFeature;
Expand Down Expand Up @@ -195,10 +196,9 @@ public void declareDefaultFeatures()
featureModel.declareFeature( new SpotFrameFeature() );
featureModel.declareFeature( new SpotNLinksFeature() );
featureModel.declareFeature( new LinkTargetIdFeature( modelGraph ) );
featureModel.declareFeature(
new LinkDisplacementFeature( modelGraph, Dimension.LENGTH.getUnits( spaceUnits, timeUnits ) ) );
featureModel.declareFeature(
new LinkVelocityFeature( modelGraph, Dimension.VELOCITY.getUnits( spaceUnits, timeUnits ) ) );
featureModel.declareFeature( new LinkDisplacementFeature( modelGraph, Dimension.LENGTH.getUnits( spaceUnits, timeUnits ) ) );
featureModel.declareFeature( new LinkVelocityFeature( modelGraph, Dimension.VELOCITY.getUnits( spaceUnits, timeUnits ) ) );
featureModel.declareFeature( new LinkDeltaFrameFeature( modelGraph ) );
featureModel.declareFeature( new BranchNDivisionsFeature() );
}

Expand Down

0 comments on commit f8368f4

Please sign in to comment.