diff --git a/pom.xml b/pom.xml index 3d5cfd9..2c0445a 100755 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,11 @@ - + 4.0.0 - sc.fiji - pom-indago - 2.2.18 + org.scijava + pom-scijava + 30.0.0 @@ -15,6 +15,11 @@ deploy-to-scijava + 0.11.0 + 0.2.0-SNAPSHOT + 0.1.2 + 8.1.0 + com.indago @@ -41,6 +46,7 @@ com.indago indago-ui-elements + ${indago-ui-elements.version} io.scif @@ -50,6 +56,15 @@ net.imglib2 imglib2-ij + + net.imglib2 + imglib2-roi + + + net.imglib2 + imglib2-roi-io + ${imglib2-roi-io.version} + nz.ac.waikato.cms.weka weka-dev @@ -57,6 +72,7 @@ com.gurobi gurobi-jar + ${gurobi-jar.version} mpicbg @@ -72,8 +88,8 @@ com.miglayout - miglayout - swing + miglayout-swing + ${miglayout-swing.version} @@ -139,13 +155,17 @@ + + scijava.public + https://maven.scijava.org/content/groups/public + imagej.public - http://maven.scijava.org/content/groups/public + https://maven.scijava.org/content/groups/public erichseifert.de - http://mvn.erichseifert.de/maven2 + https://mvn.erichseifert.de/maven2 diff --git a/src/main/java/com/indago/data/segmentation/LabelData.java b/src/main/java/com/indago/data/segmentation/LabelData.java index 8551c85..76f015e 100644 --- a/src/main/java/com/indago/data/segmentation/LabelData.java +++ b/src/main/java/com/indago/data/segmentation/LabelData.java @@ -1,5 +1,7 @@ package com.indago.data.segmentation; +import gnu.trove.list.TIntList; +import gnu.trove.list.array.TIntArrayList; import java.util.ArrayList; /** @@ -22,7 +24,9 @@ public class LabelData { private LabelingTreeNode labelingTreeNode; - private final ArrayList< Integer > fragmentIndices; + private final TIntList fragmentIndices; + + private String segmentSource; LabelData() { this( createId() ); @@ -33,7 +37,8 @@ public class LabelData { useId( id ); segment = null; labelingTreeNode = null; - fragmentIndices = new ArrayList<>(); + fragmentIndices = new TIntArrayList(); + segmentSource = null; } void setSegment( final LabelingSegment segment ) { @@ -52,7 +57,7 @@ public LabelingTreeNode getLabelingTreeNode() { return labelingTreeNode; } - public ArrayList< Integer > getFragmentIndices() { + public TIntList getFragmentIndices() { return fragmentIndices; } @@ -70,4 +75,14 @@ private static synchronized void useId( final int id ) { if ( nextId < id + 1 ) nextId = id + 1; } + + public void setSegmentSource( String source ) { + this.segmentSource = source; + + } + + public String getSegmentSource() { + return segmentSource; + } + } diff --git a/src/main/java/com/indago/data/segmentation/LabelingBuilder.java b/src/main/java/com/indago/data/segmentation/LabelingBuilder.java index df1663f..b7e91df 100644 --- a/src/main/java/com/indago/data/segmentation/LabelingBuilder.java +++ b/src/main/java/com/indago/data/segmentation/LabelingBuilder.java @@ -30,7 +30,22 @@ public LabelingBuilder( final LabelingPlus labelingPlus ) { super( labelingPlus ); } - public synchronized < T extends TreeNode< T > & Iterable< ? extends Localizable > > LabelingForest buildLabelingForest( final Forest< T > forest ) { + public synchronized < T extends TreeNode< T > & Iterable< ? extends Localizable > > LabelingForest buildLabelingForest( + final Forest< T > forest ) { + String segmentationSource = ""; + return buildingLabelingForestWithSegmentationSource( forest, segmentationSource ); + } + + private < T extends TreeNode< T > & Iterable< ? extends Localizable > > LabelingForest buildingLabelingForestWithSegmentationSource( + final Forest< T > forest, + String segmentationSource ) { + + return buildingLabelingForestWithSegmentationSource( forest, segmentationSource ); + } + + public synchronized < T extends TreeNode< T > & Iterable< ? extends Localizable > > LabelingForest buildLabelingForest( + final Forest< T > forest, + String segmentationSource ) { // invalidate fragments and segments because we will add new labels fragments = null; segments = null; @@ -61,7 +76,7 @@ public LabelingBuilder( final LabelingPlus labelingPlus ) { // build a LabelingForest using the structure of the original forest final HashSet< LabelingTreeNode > roots = new HashSet<>(); for ( final T node : forest.roots() ) - roots.add( buildLabelingTreeNodeFor( node, nodeToLabel ) ); + roots.add( buildLabelingTreeNodeFor( node, nodeToLabel, segmentationSource ) ); // add new forest to list of forests ever added final LabelingForest labelingForest = new LabelingForest( roots ); @@ -70,12 +85,15 @@ public LabelingBuilder( final LabelingPlus labelingPlus ) { return labelingForest; } - private < T extends TreeNode< T > > LabelingTreeNode buildLabelingTreeNodeFor( final T node, final HashMap< T, LabelData > nodeToLabel ) { + private < T extends TreeNode< T > > LabelingTreeNode buildLabelingTreeNodeFor( + final T node, + final HashMap< T, LabelData > nodeToLabel, + final String segmentationSource ) { final LabelData label = nodeToLabel.get( node ); - createSegmentAndTreeNode( label ); + createSegmentAndTreeNode( label, segmentationSource ); final LabelingTreeNode ltn = label.getLabelingTreeNode(); for ( final T c : node.getChildren() ) - ltn.addChild( buildLabelingTreeNodeFor( c, nodeToLabel ) ); + ltn.addChild( buildLabelingTreeNodeFor( c, nodeToLabel, segmentationSource ) ); return ltn; } } diff --git a/src/main/java/com/indago/data/segmentation/LabelingPlus.java b/src/main/java/com/indago/data/segmentation/LabelingPlus.java index 3b736cf..2f06ec5 100644 --- a/src/main/java/com/indago/data/segmentation/LabelingPlus.java +++ b/src/main/java/com/indago/data/segmentation/LabelingPlus.java @@ -1,14 +1,18 @@ package com.indago.data.segmentation; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import net.imglib2.Cursor; import net.imglib2.Dimensions; import net.imglib2.img.Img; import net.imglib2.roi.labeling.ImgLabeling; import net.imglib2.roi.labeling.LabelRegion; import net.imglib2.roi.labeling.LabelRegions; import net.imglib2.roi.labeling.LabelingMapping; +import net.imglib2.roi.labeling.LabelingType; import net.imglib2.type.numeric.integer.IntType; import net.imglib2.util.Util; @@ -34,13 +38,20 @@ public class LabelingPlus public LabelingPlus( final Dimensions dimensions ) { indexImg = Util.getArrayOrCellImgFactory( dimensions, intType ).create( dimensions, intType ); labeling = new ImgLabeling<>( indexImg ); - labelRegions = new LabelRegions< LabelData >( labeling ); - labelingForests = new ArrayList< LabelingForest >(); + labelRegions = new LabelRegions<>( labeling ); + labelingForests = new ArrayList<>(); } public LabelingPlus( final Img< IntType > indexImg ) { this.indexImg = indexImg; labeling = new ImgLabeling<>( indexImg ); + labelRegions = new LabelRegions<>( labeling ); + labelingForests = new ArrayList<>(); + } + + public LabelingPlus( final Img< IntType > indexImg, final ImgLabeling labeling ) { + this.indexImg = indexImg; + this.labeling = labeling; labelRegions = new LabelRegions< LabelData >( labeling ); labelingForests = new ArrayList< LabelingForest >(); } @@ -69,7 +80,8 @@ public synchronized ArrayList< LabelingFragment > getFragments() { if ( fragments == null ) { fragments = new ArrayList<>(); final LabelingMapping< LabelData > mapping = labeling.getMapping(); - for ( final LabelData label : mapping.getLabels() ) + final Set< LabelData > labels = mapping.getLabels(); + for ( final LabelData label : labels ) label.getFragmentIndices().clear(); final int numLabelSets = mapping.numSets(); final boolean[] flags = new boolean[ numLabelSets ]; @@ -99,12 +111,58 @@ public synchronized ArrayList< LabelingSegment > getSegments() { return segments; } - void createSegmentAndTreeNode( final LabelData label ) + void createSegmentAndTreeNode( final LabelData label, final String source ) { - final LabelRegion< LabelData > labelRegion = labelRegions.getLabelRegion( label ); - final LabelingSegment segment = new LabelingSegment( labelRegion ); + final LabelingSegment segment = new LabelingSegment( () -> labelRegions.getLabelRegion( label ) ); label.setSegment( segment ); + label.setSegmentSource( source ); final LabelingTreeNode ltn = new LabelingTreeNode( segment, label ); label.setLabelingTreeNode( ltn ); } + + /** + * "Compress" labeling by removing (from mapping and index image) label sets that don't occur in the index image. + *

+ * TODO: + * - move to imglib2-roi ImgLabeling + * - parallelize indexImg remapping using Parallelization/LoopBuilder + * - increment modcount + */ + public synchronized void pack() + { + final LabelingMapping< LabelData > mapping = labeling.getMapping(); + + // indexMap[ oldIndex ] == newIndex + final int[] indexMap = new int[ mapping.numSets() ]; + final int[] inverseIndexMap = new int[ mapping.numSets() ]; + + int nextIndex = 1; + final Cursor< IntType > c = indexImg.cursor(); + while ( c.hasNext() ) + { + final IntType type = c.next(); + final int oldIndex = type.get(); + if ( oldIndex != 0 ) + { + int newIndex = indexMap[ oldIndex ]; + if ( newIndex == 0 ) + { + newIndex = nextIndex++; + indexMap[ oldIndex ] = newIndex; + inverseIndexMap[ newIndex ] = oldIndex; + } + type.set( newIndex ); + } + } + final int numLabelSets = nextIndex; + + final List< Set< LabelData > > labelSets = new ArrayList<>( numLabelSets ); + labelSets.add( new HashSet<>() ); + for ( int i = 1; i < numLabelSets; i++ ) + labelSets.add( new HashSet<>( mapping.labelsAtIndex( inverseIndexMap[ i ] ) ) ); + mapping.setLabelSets( labelSets ); + + LabelingType< LabelData > t = labeling.firstElement(); + t.set( t ); + } } diff --git a/src/main/java/com/indago/data/segmentation/LabelingSegment.java b/src/main/java/com/indago/data/segmentation/LabelingSegment.java index d011de6..da9f95d 100644 --- a/src/main/java/com/indago/data/segmentation/LabelingSegment.java +++ b/src/main/java/com/indago/data/segmentation/LabelingSegment.java @@ -1,5 +1,6 @@ package com.indago.data.segmentation; +import java.util.function.Supplier; import net.imglib2.Cursor; import net.imglib2.RandomAccess; import net.imglib2.RealLocalizable; @@ -16,10 +17,12 @@ */ public class LabelingSegment implements Segment { - private final LabelRegion< LabelData > region; + private final Supplier< LabelRegion< LabelData > > regionSupplier; - protected LabelingSegment( final LabelRegion< LabelData > region ) { - this.region = region; + private LabelRegion< LabelData > region = null; + + protected LabelingSegment( final Supplier< LabelRegion< LabelData > > region ) { + this.regionSupplier = region; } /** @@ -30,23 +33,23 @@ protected LabelingSegment( final LabelRegion< LabelData > region ) { * @return unique serialization id of the backing {@code LabelRegion}. */ public int getId() { - return region.getLabel().getId(); + return region().getLabel().getId(); } @Override public long getArea() { - return region.size(); + return region().size(); } @Override public RealLocalizable getCenterOfMass() { - return region.getCenterOfMass(); + return region().getCenterOfMass(); } @Override public IterableRegion< ? > getRegion() { - return region; + return region(); } /** @@ -57,10 +60,10 @@ public RealLocalizable getCenterOfMass() { public boolean conflictsWith( final Segment segment ) { final IterableRegion< ? > segmentRegion = segment.getRegion(); if ( segment instanceof LabelingSegment ) - if ( Intervals.isEmpty( Intervals.intersect( this.region, segmentRegion ) ) ) + if ( Intervals.isEmpty( Intervals.intersect( this.region(), segmentRegion ) ) ) return false; - final RandomAccess< BoolType > raMask = region.randomAccess(); + final RandomAccess< BoolType > raMask = region().randomAccess(); final Cursor< ? > cSegment = segmentRegion.cursor(); while ( cSegment.hasNext() ) { cSegment.fwd(); @@ -84,4 +87,21 @@ public String toString() { } return ret; } + + public String getSegmentationSource() { + return region.getLabel().getSegmentSource(); + } + + private LabelRegion< LabelData > region() + { + if ( region == null ) + { + synchronized ( this ) + { + if ( region == null ) + region = regionSupplier.get(); + } + } + return region; + } } diff --git a/src/main/java/com/indago/data/segmentation/MinimalOverlapConflictGraph.java b/src/main/java/com/indago/data/segmentation/MinimalOverlapConflictGraph.java index a3e06b2..d401d3d 100644 --- a/src/main/java/com/indago/data/segmentation/MinimalOverlapConflictGraph.java +++ b/src/main/java/com/indago/data/segmentation/MinimalOverlapConflictGraph.java @@ -1,5 +1,6 @@ package com.indago.data.segmentation; +import gnu.trove.list.TIntList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -68,8 +69,8 @@ public static ArrayList< ArrayList< LabelingSegment > > getConflictGraphCliques( Arrays.fill( heads, 1, numLists, 0 ); heads[ 0 ] = -1; int currListIndex, firstListElem, currListElem; - ArrayList< Integer > currList; - final ArrayList< Integer > firstList = intersect.get( 0 ).getFragmentIndices(); + TIntList currList; + final TIntList firstList = intersect.get( 0 ).getFragmentIndices(); A2: while ( true ) { if ( ++heads[ 0 ] >= firstList.size() ) { // done. we found all elements of the intersection. diff --git a/src/main/java/com/indago/data/segmentation/PairwiseConflictGraph.java b/src/main/java/com/indago/data/segmentation/PairwiseConflictGraph.java index 6dbbb83..08ddcb9 100644 --- a/src/main/java/com/indago/data/segmentation/PairwiseConflictGraph.java +++ b/src/main/java/com/indago/data/segmentation/PairwiseConflictGraph.java @@ -1,5 +1,6 @@ package com.indago.data.segmentation; +import gnu.trove.list.TIntList; import java.util.ArrayList; import java.util.Collection; @@ -36,7 +37,10 @@ public static ArrayList< ArrayList< LabelingSegment > > getConflictGraphCliques( final LabelData sli = segmentLabels.get( i ); for ( int j = i + 1; j < numSegments; ++j ) { final LabelData slj = segmentLabels.get( j ); - for ( final Integer fj : slj.getFragmentIndices() ) { + final TIntList fragmentIndices = slj.getFragmentIndices(); + for ( int k = 0; k < fragmentIndices.size(); k++ ) + { + int fj = fragmentIndices.get( k ); if ( sli.getFragmentIndices().contains( fj ) ) { final ArrayList< LabelingSegment > clique = new ArrayList<>(); clique.add( sli.getSegment() ); diff --git a/src/main/java/com/indago/data/segmentation/XmlIoLabelingPlus.java b/src/main/java/com/indago/data/segmentation/XmlIoLabelingPlus.java index 2ff07a4..1567eb1 100644 --- a/src/main/java/com/indago/data/segmentation/XmlIoLabelingPlus.java +++ b/src/main/java/com/indago/data/segmentation/XmlIoLabelingPlus.java @@ -1,13 +1,25 @@ package com.indago.data.segmentation; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - +import java.util.*; +import java.util.function.LongFunction; +import java.util.function.ToLongFunction; +import java.util.stream.Collectors; + +import com.indago.data.segmentation.groundtruth.FlatForest; +import com.indago.data.segmentation.groundtruth.ImageRegions; +import net.imglib2.roi.io.labeling.LabelingIOService; +import net.imglib2.roi.io.labeling.data.ImgLabelingContainer; +import net.imglib2.roi.io.labeling.data.LabelingContainer; +import net.imglib2.roi.labeling.ImgLabeling; +import org.apache.commons.lang.StringUtils; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.input.SAXBuilder; @@ -35,6 +47,7 @@ import net.imglib2.type.numeric.integer.IntType; import net.imglib2.type.numeric.real.FloatType; import net.imglib2.view.Views; +import org.scijava.plugin.Parameter; /** * @author tpietzsch, jug @@ -42,6 +55,8 @@ public class XmlIoLabelingPlus { public static final String SEGMENTLABELING_TAG = "SegmentLabeling"; + public static final String SEGMENTLABELING_VERSION_ATTRIBUTE_NAME = "version"; + public static final String SEGMENTLABELING_VERSION_ATTRIBUTE_CURRENT = "0.2"; public static final String BASEPATH_TAG = "BasePath"; public static final String INDEXIMG_TAG = "IndexImgFile"; @@ -49,6 +64,8 @@ public class XmlIoLabelingPlus { public static final String LABELS_TAG = "Labels"; public static final String MAPPING_TAG = "Mapping"; + public static final String MAPPING_BINARY_ATTRIBUTE_NAME = "binary"; + public static final String LABELMAPFILE_TAG = "MappingFile"; public static final String MAPPING_ENTRY_TAG = "MappingEntry"; public static final String MAPPING_ENTRY_INDEX_TAG = "Index"; public static final String MAPPING_ENTRY_LABELS_TAG = "Labels"; @@ -62,6 +79,72 @@ public class XmlIoLabelingPlus { public static boolean openIndexImageWithIJ = true; + @Parameter + public LabelingIOService labelingIOService; + + public LabelingBuilder loadFromBson( final String bsonFilename ) { + ImgLabelingContainer imgLabelingContainer = labelingIOService.open(bsonFilename); + ImgLabeling imgLabeling = imgLabelingContainer.getImgLabeling(); + List> labelSets = imgLabeling.getMapping().getLabelSets(); + List> recastLabelSets = new LinkedList<>(); + List recastLabels = new LinkedList<>(); + for(Set labelSet : labelSets){ + Set newLabelSet = new HashSet<>(); + for(Integer label : labelSet){ + LabelData labelData = new LabelData(label); + //TODO: set data, maybe? + + newLabelSet.add(labelData); + recastLabels.add(labelData); + } + recastLabelSets.add(newLabelSet); + } + imgLabeling = ImgLabeling.fromImageAndLabelSets(imgLabeling.getIndexImg(), recastLabelSets); + LabelingPlus labelingPlus = new LabelingPlus(ImgView.wrap( imgLabeling.getIndexImg(), null ), imgLabeling); + Map> sourceToLabel = imgLabelingContainer.getSourceToLabel(); + final LabelingBuilder labelingBuilder = new LabelingBuilder( labelingPlus ); + + for(Map.Entry> entry : sourceToLabel.entrySet()){ + if(StringUtils.isNotEmpty(entry.getKey())){ + HashSet labelingTreeNodes = new HashSet<>(); + labelingPlus.getSegments(); + + //labelingPlus.getLabeling().getMapping().getLabels().stream().filter(labelData -> labelData.); + + //TODO: iterate over all segments + for(Integer segmentId : entry.getValue()){ + Set labelDataSets = labelingPlus.getLabeling().getMapping().getLabelSets().get(segmentId); + for(LabelData labelData : labelDataSets){ + labelingPlus.createSegmentAndTreeNode(labelData, entry.getKey()); + labelingTreeNodes.add(labelData.getLabelingTreeNode()); + } + } + final LabelingForest labelingForest = new LabelingForest(labelingTreeNodes); + labelingBuilder.labelingForests.add(labelingForest); + } + + } + labelingPlus.getSegments(); + + + + + return labelingBuilder; + } + + public LabelingPlus loadFromBson( final String bsonFilename, final LongFunction idToLabel) { + ImgLabelingContainer imgLabelingContainer = labelingIOService.open(bsonFilename, idToLabel); + ImgLabeling imgLabeling = imgLabelingContainer.getImgLabeling(); + LabelingPlus labelingPlus = new LabelingPlus(ImgView.wrap( imgLabeling.getIndexImg(), null ), imgLabeling); + return labelingPlus; + } + + public void saveAsBson(final LabelingPlus labelingPlus, final String bsonFilename, final ToLongFunction labelToId) { + ImgLabelingContainer container = new ImgLabelingContainer(); + container.setImgLabeling(labelingPlus.labeling); + labelingIOService.save(container, bsonFilename, labelToId); + } + public LabelingPlus load( final String xmlFilename ) throws IOException { return load( new File( xmlFilename ) ); } @@ -84,7 +167,7 @@ public LabelingPlus load( final File xmlFile ) throws IOException { indexImgFile.getAbsolutePath(), new ArrayImgFactory<>( new IntType() ) ).get( 0 ).getImg(); final LabelingPlus labelingPlus = new LabelingPlus( indexImg ); - fromXml( root, labelingPlus ); + fromXml( root, labelingPlus, basePath ); return labelingPlus; } @@ -94,16 +177,23 @@ public void save( final LabelingPlus labelingData, final String xmlFilename ) final String indexImgFilename = xmlFilename.substring( 0, xmlFilename.length() - ".xml".length() ) + ".tif"; final File indexImgFile = new File( indexImgFilename ); - final Document doc = new Document( toXml( labelingData, xmlFileDirectory, indexImgFile ) ); + final String labelingMappingFilename = + xmlFilename.substring( 0, xmlFilename.length() - ".xml".length() ) + ".labelmap"; + final File labelingMappingFile = new File( labelingMappingFilename ); + final Document doc = new Document( toXml( labelingData, xmlFileDirectory, indexImgFile, labelingMappingFile ) ); final XMLOutputter xout = new XMLOutputter( Format.getPrettyFormat() ); xout.output( doc, new FileOutputStream( xmlFilename ) ); + writeLabelingMapping( labelingData.getLabeling().getMapping(), labelingMappingFile ); + final Img< IntType > img = ImgView.wrap( labelingData.getLabeling().getIndexImg(), null ); ImageSaver.saveAsTiff( indexImgFilename, img ); } - private void fromXml( final Element segmentLabeling, final LabelingPlus labelingPlus ) + private void fromXml( final Element segmentLabeling, final LabelingPlus labelingPlus, final File basePath ) throws IOException { + final String version = segmentLabeling.getAttributeValue( SEGMENTLABELING_VERSION_ATTRIBUTE_NAME, "0" ); + final TIntObjectMap< LabelData > idToLabelMap = getIdToLabelMap( segmentLabeling, LABELS_TAG ); @@ -111,19 +201,30 @@ private void fromXml( final Element segmentLabeling, final LabelingPlus labeling if ( mapping == null ) throw new IOException( "no <" + MAPPING_TAG + "> element found." ); - final ArrayList< Set< LabelData > > labelSets = new ArrayList<>(); - for ( final Element entry : mapping.getChildren( MAPPING_ENTRY_TAG ) ) { - final int i = XmlHelpers.getInt( entry, MAPPING_ENTRY_INDEX_TAG ); - final int[] ids = XmlHelpers.getIntArray( entry, MAPPING_ENTRY_LABELS_TAG ); - final HashSet< LabelData > labelSet = new HashSet<>( ids.length ); - for ( final int id : ids ) - labelSet.add( idToLabelMap.get( id ) ); - - while ( labelSets.size() <= i ) - labelSets.add( null ); - labelSets.set( i, labelSet ); + final ArrayList< Set< LabelData > > labelSets; + final boolean binary = Boolean.parseBoolean( mapping.getAttributeValue( "binary" ) ); + if ( binary && Objects.equals( version, SEGMENTLABELING_VERSION_ATTRIBUTE_CURRENT ) ) + { + final File labelingMappingFile = XmlHelpers.loadPath( mapping, LABELMAPFILE_TAG, basePath ); + labelSets = readLabelingMapping( labelingMappingFile, idToLabelMap ); + } + else + { + labelSets = new ArrayList<>(); + for ( final Element entry : mapping.getChildren( MAPPING_ENTRY_TAG ) ) + { + final int i = XmlHelpers.getInt( entry, MAPPING_ENTRY_INDEX_TAG ); + final int[] ids = XmlHelpers.getIntArray( entry, MAPPING_ENTRY_LABELS_TAG ); + final HashSet< LabelData > labelSet = new HashSet<>( ids.length ); + for ( final int id : ids ) + labelSet.add( idToLabelMap.get( id ) ); + + while ( labelSets.size() <= i ) + labelSets.add( null ); + labelSets.set( i, labelSet ); + } } - new SegmentLabelingSerialisation( labelingPlus.getLabeling().getMapping() ).setLabelSets( labelSets ); + labelingPlus.getLabeling().getMapping().setLabelSets( labelSets ); final Element labelingtree = segmentLabeling.getChild( LABELINGTREE_TAG ); if ( labelingtree == null ) @@ -133,12 +234,12 @@ private void fromXml( final Element segmentLabeling, final LabelingPlus labeling final int id = XmlHelpers.getInt( node, LABELINGTREE_NODE_ID_TAG ); final LabelData label = idToLabelMap.get( id ); if ( label.getLabelingTreeNode() == null ) - labelingPlus.createSegmentAndTreeNode( label ); + labelingPlus.createSegmentAndTreeNode( label, "" ); final LabelingTreeNode ltn = label.getLabelingTreeNode(); for ( final int childId : XmlHelpers.getIntArray( node, LABELINGTREE_NODE_CHILDREN_TAG ) ) { final LabelData childLabel = idToLabelMap.get( childId ); if ( childLabel.getLabelingTreeNode() == null ) - labelingPlus.createSegmentAndTreeNode( childLabel ); + labelingPlus.createSegmentAndTreeNode( childLabel, "" ); ltn.addChild( childLabel.getLabelingTreeNode() ); } } @@ -156,9 +257,18 @@ private Element toXml( final LabelingPlus labelingPlus, final File xmlFileDirectory, final File indexImgFile ) { + return toXml( labelingPlus, xmlFileDirectory, indexImgFile, null ); + } + + private Element toXml( + final LabelingPlus labelingPlus, + final File xmlFileDirectory, + final File indexImgFile, + final File labelingMappingFile ) { final LabelingMapping< LabelData > mapping = labelingPlus.getLabeling().getMapping(); final Element segmentLabeling = new Element( SEGMENTLABELING_TAG ); + segmentLabeling.setAttribute( SEGMENTLABELING_VERSION_ATTRIBUTE_NAME, SEGMENTLABELING_VERSION_ATTRIBUTE_CURRENT ); segmentLabeling.addContent( XmlHelpers.pathElement( BASEPATH_TAG, xmlFileDirectory, @@ -170,12 +280,25 @@ private Element toXml( segmentLabeling.addContent( labelIdsElement( LABELS_TAG, mapping.getLabels() ) ); final Element indexMap = new Element( MAPPING_TAG ); - int i = 0; - for ( final Set< LabelData > labelSet : new SegmentLabelingSerialisation( mapping ).getLabelSets() ) { - final Element entry = new Element( MAPPING_ENTRY_TAG ); - entry.addContent( XmlHelpers.intElement( MAPPING_ENTRY_INDEX_TAG, i++ ) ); - entry.addContent( labelIdsElement( MAPPING_ENTRY_LABELS_TAG, labelSet ) ); - indexMap.addContent( entry ); + if ( labelingMappingFile != null ) + { + indexMap.setAttribute( MAPPING_BINARY_ATTRIBUTE_NAME, "true" ); + indexMap.addContent( XmlHelpers.pathElement( + LABELMAPFILE_TAG, + labelingMappingFile, + xmlFileDirectory ) ); + } + else + { + indexMap.setAttribute( MAPPING_BINARY_ATTRIBUTE_NAME, "false" ); + int i = 0; + for ( final Set< LabelData > labelSet : mapping.getLabelSets() ) + { + final Element entry = new Element( MAPPING_ENTRY_TAG ); + entry.addContent( XmlHelpers.intElement( MAPPING_ENTRY_INDEX_TAG, i++ ) ); + entry.addContent( labelIdsElement( MAPPING_ENTRY_LABELS_TAG, labelSet ) ); + indexMap.addContent( entry ); + } } segmentLabeling.addContent( indexMap ); @@ -187,6 +310,59 @@ private Element toXml( return segmentLabeling; } + /** + * File format: + * int: number of labelsets + * (labelset*) + * labelset := + * int: index of labelset + * int: number of labels n + * int[n]: label ids + */ + private void writeLabelingMapping( final LabelingMapping< LabelData > mapping, final File labelingMappingFile ) throws IOException + { + try ( final DataOutputStream dos = new DataOutputStream( + new BufferedOutputStream( + new FileOutputStream( labelingMappingFile ), + 1024 * 1024 ) ) ) + { + final List< Set< LabelData > > labelSets = mapping.getLabelSets(); + dos.writeInt( labelSets.size() ); + int i = 0; + for ( final Set< LabelData > labelSet : labelSets ) + { + dos.writeInt( i++ ); + dos.writeInt( labelSet.size() ); + for ( final LabelData label : labelSet ) + dos.writeInt( label.getId() ); + } + } + } + + private ArrayList< Set< LabelData > > readLabelingMapping( final File labelingMappingFile, final TIntObjectMap< LabelData > idToLabelMap ) throws IOException + { + try ( final DataInputStream dis = new DataInputStream( + new BufferedInputStream( + new FileInputStream( labelingMappingFile ), + 1024 * 1024 ) ) ) + { + final int numLabelSets = dis.readInt(); + final ArrayList< Set< LabelData > > labelSets = new ArrayList<>( numLabelSets ); + for ( int i = 0; i < numLabelSets; ++i ) + { + final int index = dis.readInt(); + final int numLabels = dis.readInt(); + final HashSet< LabelData > labelSet = new HashSet<>( numLabels ); + for ( int j = 0; j < numLabels; j++ ) + labelSet.add( idToLabelMap.get( dis.readInt() ) ); + while ( labelSets.size() <= index ) + labelSets.add( null ); + labelSets.set( i, labelSet ); + } + return labelSets; + } + } + private File loadBasePath( final Element root, final File xmlFile ) { File xmlFileParentDirectory = xmlFile.getParentFile(); if ( xmlFileParentDirectory == null ) xmlFileParentDirectory = new File( "." ); @@ -270,23 +446,4 @@ private static ArrayImg< IntType, IntArray > openIntImageFastButDangerous( final out.next().set( ( int ) in.next().get() ); return img; } - - private static class SegmentLabelingSerialisation - extends - LabelingMapping.SerialisationAccess< LabelData > { - - public SegmentLabelingSerialisation( final LabelingMapping< LabelData > mapping ) { - super( mapping ); - } - - @Override - protected List< Set< LabelData > > getLabelSets() { - return super.getLabelSets(); - } - - @Override - protected void setLabelSets( final List< Set< LabelData > > labelSets ) { - super.setLabelSets( labelSets ); - } - } } diff --git a/src/main/java/com/indago/data/segmentation/groundtruth/FlatForest.java b/src/main/java/com/indago/data/segmentation/groundtruth/FlatForest.java index 0db303c..aed32bf 100644 --- a/src/main/java/com/indago/data/segmentation/groundtruth/FlatForest.java +++ b/src/main/java/com/indago/data/segmentation/groundtruth/FlatForest.java @@ -1,5 +1,6 @@ package com.indago.data.segmentation.groundtruth; +import com.indago.data.segmentation.groundtruth.ImageRegions.ImageRegion; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; @@ -28,9 +29,9 @@ public static class Node implements TreeNode< Node >, Iterable< Localizable > { private static final ArrayList< Node > emptyChildren = new ArrayList< Node >(); - private final Iterable< Localizable > pixels; + private final ImageRegion pixels; - private Node( final Iterable< Localizable > pixels ) { + public Node(final ImageRegion pixels) { this.pixels = pixels; } @@ -39,6 +40,11 @@ public Iterator< Localizable > iterator() { return pixels.iterator(); } + public long size() + { + return pixels.size(); + } + @Override public Node getParent() { return null; diff --git a/src/main/java/com/indago/data/segmentation/groundtruth/ImageRegions.java b/src/main/java/com/indago/data/segmentation/groundtruth/ImageRegions.java index b155ef2..9b208e7 100644 --- a/src/main/java/com/indago/data/segmentation/groundtruth/ImageRegions.java +++ b/src/main/java/com/indago/data/segmentation/groundtruth/ImageRegions.java @@ -56,6 +56,11 @@ public static class ImageRegion implements Iterable< Localizable > { this.itcode = itcode; } + public long size() + { + return itcode.getSize(); + } + @Override public Iterator< Localizable > iterator() { final long[] offset = new long[ itcode.numDimensions() ]; diff --git a/src/main/java/com/indago/io/ImageSaver.java b/src/main/java/com/indago/io/ImageSaver.java index b46dd9d..f6bd780 100644 --- a/src/main/java/com/indago/io/ImageSaver.java +++ b/src/main/java/com/indago/io/ImageSaver.java @@ -9,6 +9,7 @@ import net.imglib2.exception.IncompatibleTypeException; import net.imglib2.img.ImgView; import net.imglib2.type.numeric.RealType; +import org.scijava.Context; /** * Since loading and saving is still a hard thing to do right and the way to do @@ -39,7 +40,7 @@ public static < T extends RealType< T > > void saveAsTiff( // IO.saveImg( filename, img ); try { - new ImgSaver().saveImg( filename, ImgView.wrap( rai, null ) ); + new ImgSaver( new Context() ).saveImg( filename, ImgView.wrap( rai, null ) ); } catch ( ImgIOException | IncompatibleTypeException e ) { e.printStackTrace(); } diff --git a/src/test/java/com/indago/data/segmentation/XmlIoLabelingPlusTest.java b/src/test/java/com/indago/data/segmentation/XmlIoLabelingPlusTest.java new file mode 100644 index 0000000..efe1900 --- /dev/null +++ b/src/test/java/com/indago/data/segmentation/XmlIoLabelingPlusTest.java @@ -0,0 +1,44 @@ +package com.indago.data.segmentation; + +import net.imglib2.roi.io.labeling.LabelingIOService; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.scijava.Context; + +public class XmlIoLabelingPlusTest { + + Context context; + + @Before + public void beforeTests() { + context = new Context(); + } + + + @Test + public void testLoadFromBson() { + XmlIoLabelingPlus plus = new XmlIoLabelingPlus(); + plus.labelingIOService = context.getService(LabelingIOService.class); + LabelingPlus p = plus.loadFromBson("src/test/resources/bson/example1.bson"); + } + + @Test + public void testLoadFromBson2() { + XmlIoLabelingPlus plus = new XmlIoLabelingPlus(); + plus.labelingIOService = context.getService(LabelingIOService.class); + LabelingPlus p = plus.loadFromBson("src/test/resources/bson/example1.bson", id -> { + return new LabelData((int) id); + }); + } + + @Test + public void testSaveAsBson() { + XmlIoLabelingPlus plus = new XmlIoLabelingPlus(); + plus.labelingIOService = context.getService(LabelingIOService.class); + LabelingPlus p = plus.loadFromBson("src/test/resources/bson/example1.bson"); + plus.saveAsBson(p, "src/test/resources/bson/save_test.bson", label -> { + return ((LabelData)label).getId(); + }); + } +} \ No newline at end of file diff --git a/src/test/java/com/indago/ui/PlayGround5.java b/src/test/java/com/indago/ui/PlayGround5.java index 5e417aa..219b967 100644 --- a/src/test/java/com/indago/ui/PlayGround5.java +++ b/src/test/java/com/indago/ui/PlayGround5.java @@ -18,7 +18,7 @@ import net.imglib2.RandomAccessibleInterval; import net.imglib2.converter.Converters; import net.imglib2.converter.TypeIdentity; -import net.imglib2.display.RealARGBColorConverter; +import net.imglib2.converter.RealARGBConverter; import net.imglib2.img.Img; import net.imglib2.img.array.ArrayImgFactory; import net.imglib2.img.display.imagej.ImageJFunctions; @@ -58,8 +58,7 @@ public static < T extends RealType< T > & NativeType< T > > void doIt( final LabelingForest labelingForest = labelingBuilder.buildLabelingForest( FilteredComponentTree.buildComponentTree( segments, type, minComponentSize, maxComponentSize, maxGrowthPerStep, darkToBright ) ); final RandomAccessibleInterval< LabelingType< LabelData > > labeling = labelingBuilder.getLabeling(); - final RealARGBColorConverter< T > imageConverter = new RealARGBColorConverter.Imp0< T >( 0, 255 ); - imageConverter.setColor( new ARGBType( 0xffffffff ) ); + final RealARGBConverter< T > imageConverter = new RealARGBConverter< T >( 0, 255 ); final SegmentLabelSetARGBConverter labelingConverter = new SegmentLabelSetARGBConverter( new AlphaMixedSegmentLabelSetColor( new SegmentLabelColor() { Random rand = new Random(); @Override diff --git a/src/test/resources/bson/example1.bson b/src/test/resources/bson/example1.bson new file mode 100644 index 0000000..bc39e37 Binary files /dev/null and b/src/test/resources/bson/example1.bson differ diff --git a/src/test/resources/bson/example1.tif b/src/test/resources/bson/example1.tif new file mode 100644 index 0000000..0fe9447 Binary files /dev/null and b/src/test/resources/bson/example1.tif differ