From b628e48e0bc68c8821ece91d2d11da0b2b1e623d Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Wed, 28 Jun 2023 16:00:54 +0200 Subject: [PATCH 1/3] move idColumns from Annotation to AnnotationCreator --- .../embl/mobie/lib/annotation/Annotation.java | 3 --- .../embl/mobie/lib/image/StitchedImage.java | 10 +++++----- .../AbstractGridTransformation.java | 4 ++-- .../MergedGridTransformation.java | 7 ++++--- .../lib/table/DefaultAnnotatedSegment.java | 6 ------ .../lib/table/saw/TableSawAnnotatedRegion.java | 6 ------ .../saw/TableSawAnnotatedRegionCreator.java | 11 +++++++++++ .../table/saw/TableSawAnnotatedSegment.java | 6 ------ .../saw/TableSawAnnotatedSegmentCreator.java | 18 +++++++++++++++++- .../lib/table/saw/TableSawAnnotatedSpot.java | 6 ------ .../saw/TableSawAnnotatedSpotCreator.java | 11 +++++++++++ .../table/saw/TableSawAnnotationCreator.java | 4 ++++ .../saw/TableSawAnnotationTableModel.java | 12 +++++++----- .../AffineTransformedAnnotatedSegment.java | 6 ------ 14 files changed, 61 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/embl/mobie/lib/annotation/Annotation.java b/src/main/java/org/embl/mobie/lib/annotation/Annotation.java index 4e961005b..0edb79bbd 100644 --- a/src/main/java/org/embl/mobie/lib/annotation/Annotation.java +++ b/src/main/java/org/embl/mobie/lib/annotation/Annotation.java @@ -52,9 +52,6 @@ public interface Annotation extends Location // For adding manual annotations void setString( String columnName, String value ); - // For merging tables. - String[] idColumns(); - // Transform the spatial coordinates of this annotation. // Note that there are also methods to transform annotations, // which create a copy of the annotation; diff --git a/src/main/java/org/embl/mobie/lib/image/StitchedImage.java b/src/main/java/org/embl/mobie/lib/image/StitchedImage.java index faa7ba421..af179070e 100644 --- a/src/main/java/org/embl/mobie/lib/image/StitchedImage.java +++ b/src/main/java/org/embl/mobie/lib/image/StitchedImage.java @@ -222,12 +222,12 @@ private void setPositions( List< ? extends Image< T > > images, List< int[] > po this.positions = new ArrayList<>(); for ( int[] position : positions ) { - final int[] thisPosition = new int[ 2 ]; + final int[] zeroMinPosition = new int[ 2 ]; for ( int d = 0; d < 2; d++ ) { - thisPosition[ d ] = position[ d ] - min[ d ]; + zeroMinPosition[ d ] = position[ d ] - min[ d ]; } - this.positions.add( thisPosition ); + this.positions.add( zeroMinPosition ); } } } @@ -490,8 +490,8 @@ protected Map< Integer, List< RandomAccessibleInterval< V > > > stitchVolatileTi { final V background = volatileType.createVariable(); background.setValid( true ); - final FunctionRandomAccessible< V > stichedTimepointAtLevel = new FunctionRandomAccessible( 3, new VolatileValueFromTilesFetcherSupplier( tileStore, t, level, background ).get(), () -> volatileType.createVariable() ); - final IntervalView< V > rai = Views.interval( stichedTimepointAtLevel, getInterval( level ) ); + final FunctionRandomAccessible< V > stitchedTimepointAtLevel = new FunctionRandomAccessible( 3, new VolatileValueFromTilesFetcherSupplier( tileStore, t, level, background ).get(), () -> volatileType.createVariable() ); + final IntervalView< V > rai = Views.interval( stitchedTimepointAtLevel, getInterval( level ) ); stitched.get( t ).add( rai ); } } diff --git a/src/main/java/org/embl/mobie/lib/serialize/transformation/AbstractGridTransformation.java b/src/main/java/org/embl/mobie/lib/serialize/transformation/AbstractGridTransformation.java index ed31681be..078a72de3 100644 --- a/src/main/java/org/embl/mobie/lib/serialize/transformation/AbstractGridTransformation.java +++ b/src/main/java/org/embl/mobie/lib/serialize/transformation/AbstractGridTransformation.java @@ -34,8 +34,8 @@ public abstract class AbstractGridTransformation implements Transformation { // Serialization - public List< int[] > positions; + public List< int[] > positions; // x,y positions of the image tiles - public double margin = 0.1; // 0.1; + public double margin = 0.1; } diff --git a/src/main/java/org/embl/mobie/lib/serialize/transformation/MergedGridTransformation.java b/src/main/java/org/embl/mobie/lib/serialize/transformation/MergedGridTransformation.java index fab2aee15..6df1bfe5f 100644 --- a/src/main/java/org/embl/mobie/lib/serialize/transformation/MergedGridTransformation.java +++ b/src/main/java/org/embl/mobie/lib/serialize/transformation/MergedGridTransformation.java @@ -32,17 +32,18 @@ public class MergedGridTransformation extends AbstractGridTransformation { - // Serialization TODO: make fields private and add getter and setter methods + // Serialization public List< String > sources; // required - private String mergedGridSourceName = "merged image"; // required => name of corresponding StitchedImage - public String metadataSource; // optional, this improves performance (a lot) public boolean centerAtOrigin = false; // TODO: should actually be true, but: https://github.com/mobie/mobie-viewer-fiji/issues/685#issuecomment-1108179599 + private String mergedGridSourceName = "merged image"; // required => name of corresponding StitchedImage + // Runtime + public transient int timepoints = 1; // the number of timepoints that the sources span public transient boolean lazyLoadTables = true; diff --git a/src/main/java/org/embl/mobie/lib/table/DefaultAnnotatedSegment.java b/src/main/java/org/embl/mobie/lib/table/DefaultAnnotatedSegment.java index 80fff8f1f..abd011e28 100644 --- a/src/main/java/org/embl/mobie/lib/table/DefaultAnnotatedSegment.java +++ b/src/main/java/org/embl/mobie/lib/table/DefaultAnnotatedSegment.java @@ -157,12 +157,6 @@ public void setString( String columnName, String value ) throw new UnsupportedOperationException( "Adding values to " + this.getClass() + " is not implemented." ); } - @Override - public String[] idColumns() - { - return idColumns; - } - @Override public void transform( AffineTransform3D affineTransform3D ) { diff --git a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedRegion.java b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedRegion.java index 69f94ee6d..0d713f5cc 100644 --- a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedRegion.java +++ b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedRegion.java @@ -128,12 +128,6 @@ public String source() return source; } - @Override - public String[] idColumns() - { - return idColumns; - } - @Override public void transform( AffineTransform3D affineTransform3D ) { diff --git a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedRegionCreator.java b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedRegionCreator.java index 8254cfb9e..c23f4c6cc 100644 --- a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedRegionCreator.java +++ b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedRegionCreator.java @@ -31,6 +31,7 @@ import org.embl.mobie.lib.table.ColumnNames; import tech.tablesaw.api.Table; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -40,6 +41,7 @@ public class TableSawAnnotatedRegionCreator implements TableSawAnnotationCreator private final int timePointColumnIndex; private final double relativeDilation; private int regionIdColumnIndex; + private ArrayList< String > idColumns; public TableSawAnnotatedRegionCreator( Table table, Map< String, List< String > > regionIdToImageNames, double relativeDilation ) { @@ -48,6 +50,9 @@ public TableSawAnnotatedRegionCreator( Table table, Map< String, List< String > this.regionIdToImageNames = regionIdToImageNames; regionIdColumnIndex = columnNames.indexOf( ColumnNames.REGION_ID ); timePointColumnIndex = columnNames.indexOf( ColumnNames.TIMEPOINT ); + idColumns = new ArrayList<>(); + idColumns.add( ColumnNames.REGION_ID ); + idColumns.add( ColumnNames.TIMEPOINT ); } @Override @@ -71,4 +76,10 @@ public int[] removeColumns() { return new int[ 0 ]; } + + @Override + public List< String > getIDColumns() + { + return idColumns; + } } diff --git a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegment.java b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegment.java index 20a557b20..fec17f861 100644 --- a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegment.java +++ b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegment.java @@ -134,12 +134,6 @@ public String source() return source; } - @Override - public String[] idColumns() - { - return idColumns; - } - @Override public void transform( AffineTransform3D affineTransform3D ) { diff --git a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegmentCreator.java b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegmentCreator.java index 6274308e5..dc974b6ee 100644 --- a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegmentCreator.java +++ b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegmentCreator.java @@ -34,6 +34,7 @@ import tech.tablesaw.api.Table; import javax.annotation.Nullable; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -51,6 +52,7 @@ public class TableSawAnnotatedSegmentCreator implements TableSawAnnotationCreato private AtomicBoolean columnsInitialised = new AtomicBoolean( false ); private boolean is3D; private boolean hasBoundingBox; + private ArrayList< String > idColumns; public TableSawAnnotatedSegmentCreator( @Nullable SegmentColumnNames segmentColumnNames, @@ -59,6 +61,15 @@ public TableSawAnnotatedSegmentCreator( this.segmentColumnNames = segmentColumnNames; if ( table != null ) initColumns( table ); + + idColumns = new ArrayList< String >(); + if ( segmentColumnNames != null ) + { + idColumns.add( segmentColumnNames.labelIdColumn() ); + idColumns.add( segmentColumnNames.timePointColumn() ); + idColumns.add( segmentColumnNames.labelImageColumn() ); + } + } private synchronized void initColumns( Table table ) @@ -93,7 +104,6 @@ private synchronized void initColumns( Table table ) is3D = anchorColumnIndices.length == 3 && anchorColumnIndices[ 2 ] > -1; hasBoundingBox = bbMinColumnIndices[ 0 ] > -1; - } @Override @@ -153,4 +163,10 @@ private FinalRealInterval boundingBox( Table table, int rowIndex ) return boundingBox; } + + @Override + public List< String > getIDColumns() + { + return idColumns; + } } diff --git a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSpot.java b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSpot.java index 12c4f78d9..a3c36d1bc 100644 --- a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSpot.java +++ b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSpot.java @@ -102,12 +102,6 @@ public String source() return source; } - @Override - public String[] idColumns() - { - return idColumns; - } - @Override public void transform( AffineTransform3D affineTransform3D ) { diff --git a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSpotCreator.java b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSpotCreator.java index c1a3fe73b..3916846e2 100644 --- a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSpotCreator.java +++ b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSpotCreator.java @@ -31,6 +31,7 @@ import org.embl.mobie.lib.table.ColumnNames; import tech.tablesaw.api.Table; +import java.util.ArrayList; import java.util.List; public class TableSawAnnotatedSpotCreator implements TableSawAnnotationCreator< TableSawAnnotatedSpot > @@ -40,6 +41,7 @@ public class TableSawAnnotatedSpotCreator implements TableSawAnnotationCreator< private final int yColumnIndex; private final int zColumnIndex; private int timePointColumnIndex; + private ArrayList< String > idColumns; public TableSawAnnotatedSpotCreator( Table table ) { @@ -49,6 +51,9 @@ public TableSawAnnotatedSpotCreator( Table table ) yColumnIndex = columnNames.indexOf( ColumnNames.SPOT_Y ); zColumnIndex = columnNames.indexOf( ColumnNames.SPOT_Z ); timePointColumnIndex = columnNames.indexOf( ColumnNames.TIMEPOINT ); + idColumns = new ArrayList<>(); + idColumns.add( ColumnNames.SPOT_ID ); + idColumns.add( ColumnNames.TIMEPOINT ); } @Override @@ -77,4 +82,10 @@ public int[] removeColumns() { return new int[]{ xColumnIndex, yColumnIndex, zColumnIndex }; } + + @Override + public List< String > getIDColumns() + { + return idColumns; + } } diff --git a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotationCreator.java b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotationCreator.java index 1a895cc63..202e24ec9 100644 --- a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotationCreator.java +++ b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotationCreator.java @@ -30,10 +30,14 @@ import org.embl.mobie.lib.annotation.Annotation; +import java.util.List; + public interface TableSawAnnotationCreator< A extends Annotation > { A create( TableSawAnnotationTableModel< A > tableModel, int rowIndex ); int[] removeColumns(); + + List< String > getIDColumns(); } diff --git a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotationTableModel.java b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotationTableModel.java index 778396d4c..c93b08024 100644 --- a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotationTableModel.java +++ b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotationTableModel.java @@ -171,14 +171,16 @@ private void joinTable( Table additionalTable ) { // join additional table // some columns, e.g. timepoint, are optional and thus - // are only used for merging if they are actually present + // may be missing in the parent table; + // thus we only use columns for merging that are actually present final List< String > columnNames = table.columnNames(); - final List< String > mergeByColumnNames = Arrays.stream( annotation( 0 ).idColumns() ).filter( column -> columnNames.contains( column ) ).collect( Collectors.toList() ); + //final String[] idColumns = annotation( 0 ).idColumns(); + final List< String > idColumns = annotationCreator.getIDColumns(); + final List< String > mergeByColumnNames = idColumns.stream().filter( column -> columnNames.contains( column ) ).collect( Collectors.toList() ); - // note that the below joining changes the table object, + // the below table merging changes the table object, // thus other classes that need that table object - // need to retrieve the new one using the {@code getTable()} - // method + // need to retrieve the new table using {@code getTable()} try { final List< String > additionalColumnNames = additionalTable.columnNames().stream().filter( col -> ! mergeByColumnNames.contains( col ) ).collect( Collectors.toList() ); diff --git a/src/main/java/org/embl/mobie/lib/transform/AffineTransformedAnnotatedSegment.java b/src/main/java/org/embl/mobie/lib/transform/AffineTransformedAnnotatedSegment.java index a9a6eeff1..dbb177fe6 100644 --- a/src/main/java/org/embl/mobie/lib/transform/AffineTransformedAnnotatedSegment.java +++ b/src/main/java/org/embl/mobie/lib/transform/AffineTransformedAnnotatedSegment.java @@ -144,12 +144,6 @@ public void setString( String columnName, String value ) annotatedSegment.setString( columnName, value ); } - @Override - public String[] idColumns() - { - return annotatedSegment.idColumns(); - } - @Override public void transform( AffineTransform3D affineTransform3D ) { From 9a5a915875d91415f1b73868b62e78f444681bab Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Fri, 21 Jul 2023 16:39:44 -0700 Subject: [PATCH 2/3] Determine the id columns for merging lazily --- .../mobie/lib/AnnotatedLabelImageCreator.java | 13 +++++----- .../saw/TableSawAnnotatedSegmentCreator.java | 25 ++++++++----------- src/test/java/debug/DebugIssue1044.java | 19 ++++++++++++++ 3 files changed, 36 insertions(+), 21 deletions(-) create mode 100644 src/test/java/debug/DebugIssue1044.java diff --git a/src/main/java/org/embl/mobie/lib/AnnotatedLabelImageCreator.java b/src/main/java/org/embl/mobie/lib/AnnotatedLabelImageCreator.java index e18a5a589..6eb991909 100644 --- a/src/main/java/org/embl/mobie/lib/AnnotatedLabelImageCreator.java +++ b/src/main/java/org/embl/mobie/lib/AnnotatedLabelImageCreator.java @@ -21,25 +21,26 @@ public class AnnotatedLabelImageCreator { - private final MoBIE moBIE; private AnnotationLabelImage< TableSawAnnotatedSegment > annotatedLabelImage; public AnnotatedLabelImageCreator( MoBIE moBIE, SegmentationDataSource dataSource, Image< ? > image ) { - this.moBIE = moBIE; - if ( dataSource.tableData != null ) { + //System.out.println(dataSource.getName() + ": initialising.." ); + final StorageLocation tableLocation = moBIE.getTableLocation( dataSource.tableData ); final TableDataFormat tableFormat = moBIE.getTableDataFormat( dataSource.tableData ); + //System.out.println( dataSource.getName() + ": pre-init: " + dataSource.preInit() ); + Table table = dataSource.preInit() ? TableOpener.open( tableLocation, tableFormat ) : null; - SegmentColumnNames segmentColumnNames = table != null ? - TableDataFormat.getSegmentColumnNames( table.columnNames() ) : null; + //SegmentColumnNames segmentColumnNames = table != null ? + // TableDataFormat.getSegmentColumnNames( table.columnNames() ) : null; - final TableSawAnnotatedSegmentCreator annotationCreator = new TableSawAnnotatedSegmentCreator( segmentColumnNames, table ); + final TableSawAnnotatedSegmentCreator annotationCreator = new TableSawAnnotatedSegmentCreator( table ); final TableSawAnnotationTableModel< TableSawAnnotatedSegment > tableModel = new TableSawAnnotationTableModel( dataSource.getName(), annotationCreator, tableLocation, tableFormat, table ); diff --git a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegmentCreator.java b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegmentCreator.java index dc974b6ee..694cd396f 100644 --- a/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegmentCreator.java +++ b/src/main/java/org/embl/mobie/lib/table/saw/TableSawAnnotatedSegmentCreator.java @@ -54,22 +54,11 @@ public class TableSawAnnotatedSegmentCreator implements TableSawAnnotationCreato private boolean hasBoundingBox; private ArrayList< String > idColumns; - public TableSawAnnotatedSegmentCreator( - @Nullable SegmentColumnNames segmentColumnNames, - @Nullable Table table ) + public TableSawAnnotatedSegmentCreator( @Nullable Table table ) { - this.segmentColumnNames = segmentColumnNames; + //this.segmentColumnNames = segmentColumnNames; if ( table != null ) initColumns( table ); - - idColumns = new ArrayList< String >(); - if ( segmentColumnNames != null ) - { - idColumns.add( segmentColumnNames.labelIdColumn() ); - idColumns.add( segmentColumnNames.timePointColumn() ); - idColumns.add( segmentColumnNames.labelImageColumn() ); - } - } private synchronized void initColumns( Table table ) @@ -78,8 +67,12 @@ private synchronized void initColumns( Table table ) final List< String > columnNames = table.columnNames(); - if ( segmentColumnNames == null ) - segmentColumnNames = TableDataFormat.getSegmentColumnNames( columnNames ); + segmentColumnNames = TableDataFormat.getSegmentColumnNames( columnNames ); + + idColumns = new ArrayList<>(); + idColumns.add( segmentColumnNames.labelIdColumn() ); + idColumns.add( segmentColumnNames.timePointColumn() ); + idColumns.add( segmentColumnNames.labelImageColumn() ); labelIdColumnIndex = columnNames.indexOf( segmentColumnNames.labelIdColumn() ); if ( labelIdColumnIndex == -1 ) @@ -104,6 +97,8 @@ private synchronized void initColumns( Table table ) is3D = anchorColumnIndices.length == 3 && anchorColumnIndices[ 2 ] > -1; hasBoundingBox = bbMinColumnIndices[ 0 ] > -1; + + } @Override diff --git a/src/test/java/debug/DebugIssue1044.java b/src/test/java/debug/DebugIssue1044.java new file mode 100644 index 000000000..17d84890c --- /dev/null +++ b/src/test/java/debug/DebugIssue1044.java @@ -0,0 +1,19 @@ +package debug; + +import net.imagej.ImageJ; +import org.embl.mobie.MoBIE; +import org.embl.mobie.MoBIESettings; + +import java.io.IOException; + +public class DebugIssue1044 +{ + public static void main( String[] args ) throws IOException + { + final ImageJ imageJ = new ImageJ(); + imageJ.ui().showUI(); + + new MoBIE("/Users/tischer/Downloads/minimal-mobie/minimal-mobie-project", MoBIESettings.settings().view( "segmentations" ) );// .getViewManager().show( "cell-segmentation" ); + + } +} From cc25e02bfc708b9c398913099e6e3450f9a68708 Mon Sep 17 00:00:00 2001 From: Christian Tischer Date: Fri, 21 Jul 2023 16:47:53 -0700 Subject: [PATCH 3/3] Add AnnotationListener notification for adding columns --- .../mobie/lib/table/ConcatenatedAnnotationTableModel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/embl/mobie/lib/table/ConcatenatedAnnotationTableModel.java b/src/main/java/org/embl/mobie/lib/table/ConcatenatedAnnotationTableModel.java index 6f2c7a683..cbd1793eb 100644 --- a/src/main/java/org/embl/mobie/lib/table/ConcatenatedAnnotationTableModel.java +++ b/src/main/java/org/embl/mobie/lib/table/ConcatenatedAnnotationTableModel.java @@ -106,8 +106,8 @@ public void loadTableChunk( String tableChunk ) for ( AnnotationTableModel< A > tableModel : tableModels ) tableModel.loadTableChunk( tableChunk ); - // TODO: it is not logical that this method does not trigger - // an annotation listener... + for ( AnnotationListener< A > listener : listeners.list ) + listener.columnsAdded( null ); } @Override