Skip to content

Commit

Permalink
Merge pull request #39 from mastodon-sc/branch_spot_id_feature
Browse files Browse the repository at this point in the history
Add new SpotBranchIdFeature
  • Loading branch information
stefanhahmann authored Sep 4, 2023
2 parents 3371a96 + 9639dda commit e9174be
Show file tree
Hide file tree
Showing 6 changed files with 347 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.mastodon.mamut.feature.spot;

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.FeatureProjections;
import org.mastodon.feature.FeatureSpec;
import org.mastodon.feature.IntFeatureProjection;
import org.mastodon.feature.Multiplicity;
import org.mastodon.mamut.model.Spot;
import org.mastodon.properties.IntPropertyMap;
import org.scijava.plugin.Plugin;

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

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

public class SpotBranchIDFeature implements Feature< Spot >
{

public static final String KEY = "Branch spot ID";

private static final String HELP_STRING = "Returns the ID of the branch each spot belongs to.";

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

public static final SpotBranchIDFeature.Spec SPEC = new SpotBranchIDFeature.Spec();

final IntPropertyMap< Spot > map;

private final IntFeatureProjection< Spot > projection;

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

SpotBranchIDFeature( final IntPropertyMap< Spot > map )
{
this.map = map;
this.projection = FeatureProjections.project( key( PROJECTION_SPEC ), map, Dimension.NONE_UNITS );
}

public int get( final Spot spot )
{
return map.getInt( spot );
}

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

@Override
public Set< FeatureProjection< Spot > > projections()
{
return Collections.singleton( projection );
}

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

@Override
public void invalidate( final Spot spot )
{
map.remove( spot );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*-
* #%L
* Mastodon
* %%
* Copyright (C) 2014 - 2022 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.spot;

import org.mastodon.mamut.feature.CancelableImpl;
import org.mastodon.mamut.feature.MamutFeatureComputer;
import org.mastodon.mamut.model.ModelGraph;
import org.mastodon.mamut.model.Spot;
import org.mastodon.mamut.model.branch.BranchSpot;
import org.mastodon.mamut.model.branch.ModelBranchGraph;
import org.mastodon.properties.IntPropertyMap;
import org.scijava.ItemIO;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;

@Plugin(type = MamutFeatureComputer.class)
@SuppressWarnings({ "UnusedDeclaration" })
public class SpotBranchIDFeatureComputer extends CancelableImpl implements MamutFeatureComputer
{

@Parameter
@SuppressWarnings({ "UnusedDeclaration" })
private ModelGraph graph;

@Parameter
@SuppressWarnings({ "UnusedDeclaration" })
private ModelBranchGraph branchGraph;

@Parameter(type = ItemIO.OUTPUT)
private SpotBranchIDFeature output;

@Override
public void createOutput()
{
if ( null == output )
output = new SpotBranchIDFeature( new IntPropertyMap<>( graph.vertices().getRefPool(), -1 ) );
}

@Override
public void run()
{
output.map.beforeClearPool();

if ( graph.vertices().isEmpty() )
return;
if ( branchGraph.vertices().isEmpty() )
return;

BranchSpot ref = branchGraph.vertexRef();
for ( Spot spot : graph.vertices() )
{
if ( isCanceled() )
return;
final BranchSpot branchSpot = branchGraph.getBranchVertex( spot, ref );
if ( branchSpot != null )
output.map.set( spot, branchSpot.getInternalPoolIndex() );
}
branchGraph.releaseRef( ref );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*-
* #%L
* Mastodon
* %%
* Copyright (C) 2014 - 2022 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.spot;

import org.mastodon.collection.RefCollection;
import org.mastodon.feature.io.FeatureSerializer;
import org.mastodon.io.FileIdToObjectMap;
import org.mastodon.io.ObjectToFileIdMap;
import org.mastodon.io.properties.IntPropertyMapSerializer;
import org.mastodon.mamut.model.Spot;
import org.mastodon.properties.IntPropertyMap;
import org.scijava.plugin.Plugin;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

@Plugin(type = FeatureSerializer.class)
@SuppressWarnings({ "UnusedDeclaration" })
public class SpotBranchIDFeatureSerializer implements FeatureSerializer< SpotBranchIDFeature, Spot >
{

@Override
public SpotBranchIDFeature.Spec getFeatureSpec()
{
return SpotBranchIDFeature.SPEC;
}

@Override
public void serialize(
final SpotBranchIDFeature feature, final ObjectToFileIdMap< Spot > idmap,
final ObjectOutputStream oos
) throws IOException
{
final IntPropertyMapSerializer< Spot > propertyMapSerializer = new IntPropertyMapSerializer<>( feature.map );
propertyMapSerializer.writePropertyMap( idmap, oos );
}

@Override
public SpotBranchIDFeature deserialize(
final FileIdToObjectMap< Spot > idmap, final RefCollection< Spot > pool,
final ObjectInputStream ois
) throws IOException, ClassNotFoundException
{
final IntPropertyMap< Spot > map = new IntPropertyMap<>( pool, -1 );
final IntPropertyMapSerializer< Spot > propertyMapSerializer = new IntPropertyMapSerializer<>( map );
propertyMapSerializer.readPropertyMap( idmap, ois );
return new SpotBranchIDFeature( map );
}
}
23 changes: 23 additions & 0 deletions src/test/java/org/mastodon/mamut/feature/AbstractFeatureTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.mastodon.mamut.feature;

import org.mastodon.feature.Feature;
import org.mastodon.feature.FeatureProjection;
import org.mastodon.feature.FeatureProjectionKey;
import org.mastodon.feature.FeatureProjectionSpec;

import java.io.IOException;

public abstract class AbstractFeatureTest< T >
{

protected FeatureProjection< T > getProjection( Feature< T > ellipsoidFeature, FeatureProjectionSpec featureProjectionSpec )
{
return ellipsoidFeature.project( FeatureProjectionKey.key( featureProjectionSpec ) );
}

public abstract void testFeatureComputation();

public abstract void testFeatureSerialization() throws IOException;

public abstract void testFeatureInvalidate();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.mastodon.mamut.feature.spot;

import org.junit.Before;
import org.junit.Test;
import org.mastodon.feature.Feature;
import org.mastodon.feature.FeatureProjection;
import org.mastodon.mamut.feature.AbstractFeatureTest;
import org.mastodon.mamut.feature.FeatureComputerTestUtils;
import org.mastodon.mamut.feature.FeatureSerializerTestUtils;
import org.mastodon.mamut.feature.branch.exampleGraph.ExampleGraph2;
import org.mastodon.mamut.model.Spot;
import org.scijava.Context;

import java.io.IOException;
import java.util.Collections;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;

public class SpotBranchIDFeatureTest extends AbstractFeatureTest< Spot >
{
private Feature< Spot > feature;

private final ExampleGraph2 graph = new ExampleGraph2();

@Before
public void setUp()
{
try (Context context = new Context())
{
feature = FeatureComputerTestUtils.getFeature( context, graph.getModel(), SpotBranchIDFeature.SPEC );
}
}

@Override
@Test
public void testFeatureComputation()
{
FeatureProjection< Spot > featureProjection = getProjection( feature, SpotBranchIDFeature.PROJECTION_SPEC );
assertEquals( graph.branchSpotA.getInternalPoolIndex(), ( int ) featureProjection.value( graph.spot0 ) );
assertEquals( graph.branchSpotE.getInternalPoolIndex(), ( int ) featureProjection.value( graph.spot10 ) );
}

@Override
@Test
public void testFeatureSerialization() throws IOException
{
SpotBranchIDFeature featureReloaded;
try (Context context = new Context())
{
featureReloaded = ( SpotBranchIDFeature ) FeatureSerializerTestUtils.saveAndReload( context, graph.getModel(), feature );
}
// check that the feature has correct values after saving and reloading
assertTrue( FeatureSerializerTestUtils.checkFeatureProjectionEquality( feature, featureReloaded,
Collections.singleton( graph.spot0 )
) );
}

@Override
@Test
public void testFeatureInvalidate()
{
Spot spot = graph.spot0;
// test, if features have a non "-1" value before invalidation
assertNotEquals( -1, ( int ) getProjection( feature, SpotBranchIDFeature.PROJECTION_SPEC ).value( spot ) );

// invalidate feature
feature.invalidate( spot );

// test, if features are "-1" after invalidation
assertEquals( -1, ( int ) getProjection( feature, SpotBranchIDFeature.PROJECTION_SPEC ).value( spot ) );
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
package org.mastodon.mamut.feature.spot.ellipsoid;

import org.mastodon.feature.Feature;
import org.mastodon.feature.FeatureProjection;
import org.mastodon.feature.FeatureProjectionKey;
import org.mastodon.feature.FeatureProjectionSpec;
import org.mastodon.mamut.feature.AbstractFeatureTest;
import org.mastodon.mamut.model.Model;
import org.mastodon.mamut.model.ModelGraph;
import org.mastodon.mamut.model.Spot;

import java.io.IOException;

public abstract class AbstractEllipsoidFeatureTest
public abstract class AbstractEllipsoidFeatureTest extends AbstractFeatureTest< Spot >
{
protected final Model model = new Model();

Expand All @@ -36,16 +31,4 @@ private static Spot initEllipsoidSpot( ModelGraph graph )
spot.setCovariance( new double[][] { { 6, 2, 3 }, { 2, 7, 4 }, { 3, 4, 8 } } );
return spot;
}

protected static FeatureProjection< Spot > getProjection( Feature< Spot > ellipsoidFeature,
FeatureProjectionSpec featureProjectionSpec )
{
return ellipsoidFeature.project( FeatureProjectionKey.key( featureProjectionSpec ) );
}

abstract void testFeatureComputation();

abstract void testFeatureSerialization() throws IOException;

abstract void testFeatureInvalidate();
}

0 comments on commit e9174be

Please sign in to comment.