diff --git a/render-app/src/main/java/org/janelia/alignment/match/parameters/TilePairDerivationParameters.java b/render-app/src/main/java/org/janelia/alignment/match/parameters/TilePairDerivationParameters.java index 7b301fa8b..18ca201d0 100644 --- a/render-app/src/main/java/org/janelia/alignment/match/parameters/TilePairDerivationParameters.java +++ b/render-app/src/main/java/org/janelia/alignment/match/parameters/TilePairDerivationParameters.java @@ -62,6 +62,12 @@ public class TilePairDerivationParameters implements Serializable { arity = 1) public boolean excludeSameSectionNeighbors = false; + @Parameter( + names = "--excludeSameMfovNeighbors", + description = "Exclude neighbor tiles in the same layer (z) and MFOV as the source tile", + arity = 1) + public boolean excludeSameMfovNeighbors = false; + @Parameter( names = "--excludePairsInMatchCollection", description = "Name of match collection whose existing pairs should be excluded from the generated list (default is to include all pairs)" diff --git a/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/Utilities.java b/render-app/src/main/java/org/janelia/alignment/multisem/MultiSemUtilities.java similarity index 92% rename from render-ws-java-client/src/main/java/org/janelia/render/client/multisem/Utilities.java rename to render-app/src/main/java/org/janelia/alignment/multisem/MultiSemUtilities.java index 538156ac4..9d70754f8 100644 --- a/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/Utilities.java +++ b/render-app/src/main/java/org/janelia/alignment/multisem/MultiSemUtilities.java @@ -1,4 +1,4 @@ -package org.janelia.render.client.multisem; +package org.janelia.alignment.multisem; import java.io.IOException; import java.nio.file.Files; @@ -9,16 +9,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; - -import org.janelia.alignment.match.CanvasId; -import org.janelia.alignment.match.CanvasMatchResult; -import org.janelia.alignment.match.CanvasMatches; -import org.janelia.alignment.match.OrderedCanvasIdPair; -import org.janelia.alignment.spec.TileSpec; -import org.janelia.render.client.RenderDataClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import mpicbg.models.AbstractAffineModel2D; import mpicbg.models.CoordinateTransform; @@ -28,12 +18,20 @@ import mpicbg.models.Point; import mpicbg.models.PointMatch; +import org.janelia.alignment.match.CanvasId; +import org.janelia.alignment.match.CanvasMatchResult; +import org.janelia.alignment.match.CanvasMatches; +import org.janelia.alignment.match.OrderedCanvasIdPair; +import org.janelia.alignment.spec.TileSpec; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Utility methods for working with Multi-SEM data sets. * * @author Eric Trautman */ -public class Utilities { +public class MultiSemUtilities { /** * @return 0399_m0013 for w60_magc0399_scan005_m0013_s001 @@ -229,20 +227,5 @@ public static List getMatchingTransformedCornersForTile(final TileSpec ti return tileSpec.getMatchingTransformedPoints(rawLocations); } - /** - * @return list of distinct sorted MFOV names for the specified stack z-layer. - */ - public static List getMFOVNames(final RenderDataClient renderDataClient, - final String stack, - final Double z) - throws IOException { - return renderDataClient.getTileBounds(stack, z) - .stream() - .map(tileBounds -> getMFOVForTileId(tileBounds.getTileId())) - .distinct() - .sorted() - .collect(Collectors.toList()); - } - - private static final Logger LOG = LoggerFactory.getLogger(Utilities.class); + private static final Logger LOG = LoggerFactory.getLogger(MultiSemUtilities.class); } diff --git a/render-app/src/main/java/org/janelia/alignment/spec/TileBoundsRTree.java b/render-app/src/main/java/org/janelia/alignment/spec/TileBoundsRTree.java index c4f4223de..c7c33499b 100644 --- a/render-app/src/main/java/org/janelia/alignment/spec/TileBoundsRTree.java +++ b/render-app/src/main/java/org/janelia/alignment/spec/TileBoundsRTree.java @@ -17,6 +17,7 @@ import org.janelia.alignment.match.CanvasId; import org.janelia.alignment.match.OrderedCanvasIdPair; +import org.janelia.alignment.multisem.MultiSemUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -193,7 +194,8 @@ public Set getCircleNeighbors(final List source final Double explicitRadius, final boolean excludeCornerNeighbors, final boolean excludeSameLayerNeighbors, - final boolean excludeSameSectionNeighbors) { + final boolean excludeSameSectionNeighbors, + final boolean excludeSameMfovNeighbors) { String firstTileId = null; if (! sourceTileBoundsList.isEmpty()) { @@ -232,14 +234,16 @@ public Set getCircleNeighbors(final List source neighborTileIdPairs.addAll( getDistinctPairs(tileBounds, searchResults, - excludeCornerNeighbors, excludeSameSectionNeighbors, true)); + excludeCornerNeighbors, excludeSameSectionNeighbors, excludeSameMfovNeighbors, + true)); } for (final TileBoundsRTree neighborTree : neighborTrees) { searchResults = neighborTree.findTilesInCircle(circle); neighborTileIdPairs.addAll( getDistinctPairs(tileBounds, searchResults, - excludeCornerNeighbors, excludeSameSectionNeighbors, false)); + excludeCornerNeighbors, excludeSameSectionNeighbors, excludeSameMfovNeighbors, + false)); } } @@ -281,9 +285,11 @@ public static Set getDistinctPairs(final TileBounds fromTil final List toTiles, final boolean excludeCornerNeighbors, final boolean excludeSameSectionNeighbors, + final boolean excludeSameMfovNeighbors, final boolean includeRelativePosition) { final Set pairs = new HashSet<>(toTiles.size() * 2); final String pTileId = fromTile.getTileId(); + final String pMfov = excludeSameMfovNeighbors ? MultiSemUtilities.getMFOVForTileId(pTileId) : null; final double fromMinX = fromTile.getMinX(); final double fromMaxX = fromTile.getMaxX(); @@ -302,6 +308,10 @@ public static Set getDistinctPairs(final TileBounds fromTil isNeighborCenterInRange(fromMinX, fromMaxX, toTile.getMinX(), toTile.getMaxX()) || isNeighborCenterInRange(fromMinY, fromMaxY, toTile.getMinY(), toTile.getMaxY())) { + if (excludeSameMfovNeighbors && (pMfov.equals(MultiSemUtilities.getMFOVForTileId(qTileId)))) { + continue; + } + final OrderedCanvasIdPair pair; if (includeRelativePosition) { pair = OrderedCanvasIdPair.withRelativeMontagePositions(fromTile, toTile); diff --git a/render-app/src/test/java/org/janelia/alignment/multisem/MultiSemUtilitiesTest.java b/render-app/src/test/java/org/janelia/alignment/multisem/MultiSemUtilitiesTest.java new file mode 100644 index 000000000..6593703ce --- /dev/null +++ b/render-app/src/test/java/org/janelia/alignment/multisem/MultiSemUtilitiesTest.java @@ -0,0 +1,24 @@ +package org.janelia.alignment.multisem; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests the {@link MultiSemUtilities} class. + * + * @author Eric Trautman + */ +public class MultiSemUtilitiesTest { + + @Test + public void testTileIdParsers() { + final String tileId = "w60_magc0399_scan005_m0013_s001"; + Assert.assertEquals("invalid MFOVForTileId", + "0399_m0013", MultiSemUtilities.getMFOVForTileId(tileId)); + Assert.assertEquals("invalid SFOVForTileId", + "0399_m0013_s001", MultiSemUtilities.getSFOVForTileId(tileId)); + Assert.assertEquals("invalid SFOVIndexForTileId", + "001", MultiSemUtilities.getSFOVIndexForTileId(tileId)); + } + +} diff --git a/render-app/src/test/java/org/janelia/alignment/spec/TileBoundsRTreeTest.java b/render-app/src/test/java/org/janelia/alignment/spec/TileBoundsRTreeTest.java index 9455ebe90..9f873b98c 100644 --- a/render-app/src/test/java/org/janelia/alignment/spec/TileBoundsRTreeTest.java +++ b/render-app/src/test/java/org/janelia/alignment/spec/TileBoundsRTreeTest.java @@ -74,6 +74,7 @@ public void testGetCircleNeighbors() { null, false, false, + false, false); final Set expectedPairs = new TreeSet<>(); @@ -94,6 +95,7 @@ public void testGetCircleNeighbors() { explicitRadius, false, false, + false, false); expectedPairs.clear(); @@ -123,6 +125,7 @@ public void testGetCircleNeighborsWithFullyOverlappingTiles() { null, false, false, + false, false); final Set expectedPairs = new TreeSet<>(); @@ -147,17 +150,55 @@ public void testGetCanvasIdPairs() { final TileBounds centerTile = tileBoundsList.get(4); Set pairs = - TileBoundsRTree.getDistinctPairs(centerTile, tileBoundsList, false, false, false); + TileBoundsRTree.getDistinctPairs(centerTile, + tileBoundsList, + false, + false, + false, + false); int expectedNumberOfCombinations = tileBoundsList.size() - 1; // all tiles except the center Assert.assertEquals("incorrect number of combinations (with corner neighbors) in " + pairs, expectedNumberOfCombinations, pairs.size()); expectedNumberOfCombinations = expectedNumberOfCombinations - 4; // remove the 4 corner tiles - pairs = TileBoundsRTree.getDistinctPairs(centerTile, tileBoundsList, true, false, true); + pairs = TileBoundsRTree.getDistinctPairs(centerTile, + tileBoundsList, + true, + false, + false, + true); Assert.assertEquals("incorrect number of combinations (without corner neighbors) in " + pairs, expectedNumberOfCombinations, pairs.size()); } + @Test + public void testGetDifferentMFovCanvasIdPairs() { + + final Double z = 1.0; + final String sectionId = String.valueOf(z); + // s082 s083 s084 + // s071 s070 + final List tileBoundsList = Arrays.asList( + new TileBounds("w60_magc0399_scan012_m0013_s082", sectionId, z, 5.0, 0.0, 17.0, 12.0), + new TileBounds("w60_magc0399_scan012_m0013_s083", sectionId, z, 15.0, 0.0, 27.0, 12.0), + new TileBounds("w60_magc0399_scan012_m0013_s084", sectionId, z, 25.0, 0.0, 37.0, 12.0), + new TileBounds("w60_magc0399_scan012_m0014_s071", sectionId, z, 10.0, 10.0, 22.0, 22.0), + new TileBounds("w60_magc0399_scan012_m0014_s070", sectionId, z, 20.0, 10.0, 32.0, 22.0) + ); + + final TileBounds testTile = tileBoundsList.get(1); // s083 + + final Set pairs = + TileBoundsRTree.getDistinctPairs(testTile, + tileBoundsList, + false, + false, + true, + false); + Assert.assertEquals("incorrect number of combinations in " + pairs, + 2, pairs.size()); + } + @Test public void testFindCompletelyObscuredTiles() { diff --git a/render-ws-java-client/src/main/java/org/janelia/render/client/DebugTransformedCornersClient.java b/render-ws-java-client/src/main/java/org/janelia/render/client/DebugTransformedCornersClient.java index 88bf02dd2..fdade1bfe 100644 --- a/render-ws-java-client/src/main/java/org/janelia/render/client/DebugTransformedCornersClient.java +++ b/render-ws-java-client/src/main/java/org/janelia/render/client/DebugTransformedCornersClient.java @@ -98,7 +98,7 @@ public Parameters() { } public boolean hasTileIds() { - return (tileIds != null) && (tileIds.size() > 0); + return (tileIds != null) && (! tileIds.isEmpty()); } } @@ -154,7 +154,7 @@ public void runClient(final String[] args) parameters.layerRange.minZ, parameters.layerRange.maxZ, explicitZValues); - if (this.zValues.size() == 0) { + if (this.zValues.isEmpty()) { throw new IllegalArgumentException( "stack " + firstStackName + " does not contain any layers with the specified z values, " + "confirm --minZ and --maxZ are correct"); @@ -262,6 +262,7 @@ private List debugPairsForStack(final String stackName) null, false, false, + false, false); neighborPairs.addAll(currentNeighborPairs); @@ -271,7 +272,7 @@ private List debugPairsForStack(final String stackName) final List pTransformedCornersAll = new ArrayList<>(); final List qTransformedCornersAll = new ArrayList<>(); - if (neighborPairs.size() > 0) { + if (! neighborPairs.isEmpty()) { final Map zToTilesMap = new HashMap<>(zValues.size()); for (final Double zVal : zValues) { zToTilesMap.put(zVal, renderDataClient.getResolvedTiles(stackName, zVal)); @@ -329,8 +330,9 @@ private List debugPairsForStack(final String stackName) } //System.out.println( model + ", " + model.getClass().getSimpleName()); //System.exit( 0 ); - } catch (NotEnoughDataPointsException | IllDefinedDataPointsException e) { - e.printStackTrace(); + } catch (final NotEnoughDataPointsException | IllDefinedDataPointsException e) { + //noinspection CallToPrintStackTrace + e.printStackTrace(); } } @@ -366,14 +368,15 @@ private List debugPairsForStack(final String stackName) } // e.g. "[1.0, 0.0, 957.4067568339881], [0.0, 1.0, -1640.2727272727273]" - public static AffineModel2D stringToModel( String modelString ) + @SuppressWarnings("unused") + public static AffineModel2D stringToModel(String modelString ) { modelString = modelString.replace("[", "" ); modelString = modelString.replace("]", "" ); modelString = modelString.replace(" ", "" ); modelString = modelString.trim(); - String[] s = modelString.split( "," ); + final String[] s = modelString.split( "," ); final AffineModel2D model = new AffineModel2D(); model.set(Double.parseDouble(s[0]), Double.parseDouble(s[1]), Double.parseDouble(s[3]), Double.parseDouble(s[4]), Double.parseDouble(s[2]), Double.parseDouble(s[5])); @@ -417,9 +420,10 @@ public static void computeError( final List matches, final Model model.setCost( error ); System.out.println( "maxE=" + maxError + " " + model + ", " + model.getClass().getSimpleName()); - } catch (NotEnoughDataPointsException | IllDefinedDataPointsException e) { + } catch (final NotEnoughDataPointsException | IllDefinedDataPointsException e) { // TODO Auto-generated catch block - e.printStackTrace(); + //noinspection CallToPrintStackTrace + e.printStackTrace(); } } diff --git a/render-ws-java-client/src/main/java/org/janelia/render/client/ExampleMatchVisualizationClient.java b/render-ws-java-client/src/main/java/org/janelia/render/client/ExampleMatchVisualizationClient.java index 111051e93..3f0138b2f 100644 --- a/render-ws-java-client/src/main/java/org/janelia/render/client/ExampleMatchVisualizationClient.java +++ b/render-ws-java-client/src/main/java/org/janelia/render/client/ExampleMatchVisualizationClient.java @@ -170,7 +170,6 @@ public void runClient(final String[] args) throws Exception { * ('::' for existing connections and '??' for missing connections) to standard out. * This is sufficient for the single row FIB-SEM stacks with the same number of tiles in each layer. * It won't work for many other cases. - * * Since the primary goal of the client is to demonstrate how to pull tile and match data from render, * it has been left in its current less-than-ideal state. * @@ -185,7 +184,7 @@ void printConnections() final List zValues = zToSectionIdMap.keySet().stream().sorted().collect(Collectors.toList()); - if (zValues.size() == 0) { + if (zValues.isEmpty()) { throw new IllegalArgumentException( "stack " + parameters.stack + " does not contain any layers with the specified z values"); } @@ -209,7 +208,8 @@ void printConnections() null, true, false, - false) + false, + false) .stream() .map(pair -> { // Minor Hack: Remove same layer relative position data inserted by @@ -245,7 +245,8 @@ void printConnections() null, true, true, - false) + false, + false) .stream().sorted().collect(Collectors.toList()); for (final OrderedCanvasIdPair pair : crossLayerNeighborPairs) { diff --git a/render-ws-java-client/src/main/java/org/janelia/render/client/RestartSolverClient.java b/render-ws-java-client/src/main/java/org/janelia/render/client/RestartSolverClient.java index 6f96db21b..b2db6a8d8 100644 --- a/render-ws-java-client/src/main/java/org/janelia/render/client/RestartSolverClient.java +++ b/render-ws-java-client/src/main/java/org/janelia/render/client/RestartSolverClient.java @@ -11,7 +11,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import org.apache.commons.lang.math.DoubleRange; @@ -237,7 +236,7 @@ private RestartSolverClient(final Parameters parameters) } private void run() - throws IOException, ExecutionException, InterruptedException { + throws IOException { LOG.info("run: entry"); @@ -333,6 +332,7 @@ private Set getSameLayerPairs(final Map getCrossLayerPairs(final Map zToTileBounds, final List consistentLayerRanges, - final Map pairToMatchesMap) - throws ExecutionException, InterruptedException { + final Map pairToMatchesMap) { final DoubleRange currentRange = consistentLayerRanges.get(nextRangeIndex - 1); final DoubleRange nextRange = consistentLayerRanges.get(nextRangeIndex); diff --git a/render-ws-java-client/src/main/java/org/janelia/render/client/TilePairClient.java b/render-ws-java-client/src/main/java/org/janelia/render/client/TilePairClient.java index 471a0936f..873914eca 100644 --- a/render-ws-java-client/src/main/java/org/janelia/render/client/TilePairClient.java +++ b/render-ws-java-client/src/main/java/org/janelia/render/client/TilePairClient.java @@ -392,7 +392,8 @@ private void deriveAndSaveSortedNeighborPairsForZValues(final List sorte tpdp.explicitRadius, tpdp.excludeCornerNeighbors, tpdp.excludeSameLayerNeighbors, - tpdp.excludeSameSectionNeighbors); + tpdp.excludeSameSectionNeighbors, + tpdp.excludeSameMfovNeighbors); if (tpdp.excludeSameLayerPairsWithPosition != null) { final MontageRelativePosition excludedPosition = tpdp.excludeSameLayerPairsWithPosition; diff --git a/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVCrossMatchPatchClient.java b/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVCrossMatchPatchClient.java index 9640feec4..9630fe858 100644 --- a/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVCrossMatchPatchClient.java +++ b/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVCrossMatchPatchClient.java @@ -23,6 +23,7 @@ import org.janelia.alignment.match.OrderedCanvasIdPair; import org.janelia.alignment.match.RenderableCanvasIdPairs; import org.janelia.alignment.match.parameters.FeatureStorageParameters; +import org.janelia.alignment.multisem.MultiSemUtilities; import org.janelia.alignment.multisem.OrderedMFOVPair; import org.janelia.alignment.multisem.UnconnectedMFOVPairsForStack; import org.janelia.alignment.spec.ResolvedTileSpecCollection; @@ -138,7 +139,7 @@ public Path getStoragePath(final Double pZ, public void validateAndSetupDerivedValues() throws IllegalArgumentException { if (matchStorageFile != null) { - Utilities.validateMatchStorageLocation(matchStorageFile); + MultiSemUtilities.validateMatchStorageLocation(matchStorageFile); } sFOVIndexList = sFOVIndexList.stream().distinct().sorted().collect(Collectors.toList()); sFOVIndexSet = new HashSet<>(sFOVIndexList); @@ -264,7 +265,7 @@ public void deriveAndSaveMatchesForLayer(final StackId stackId, buildUnconnectedData(pZ, qZ, mFOVName); - if (unconnectedPairsForMFOV.size() > 0) { + if (! unconnectedPairsForMFOV.isEmpty()) { final String urlTemplateString = "{baseDataUrl}/owner/" + stackId.getOwner() + "/project/" + stackId.getProject() + @@ -302,10 +303,10 @@ public void buildUnconnectedData(final Double pZ, final ResolvedTileSpecCollection pResolvedTiles = zToResolvedTiles.get(pZ); final ResolvedTileSpecCollection qResolvedTiles = zToResolvedTiles.get(qZ); - final Map pSFOVToTileSpec = Utilities.mapMFOVTilesToSFOVIds(pResolvedTiles.getTileSpecs(), - mFOVName); - final Map qSFOVToTileSpec = Utilities.mapMFOVTilesToSFOVIds(qResolvedTiles.getTileSpecs(), - mFOVName); + final Map pSFOVToTileSpec = MultiSemUtilities.mapMFOVTilesToSFOVIds(pResolvedTiles.getTileSpecs(), + mFOVName); + final Map qSFOVToTileSpec = MultiSemUtilities.mapMFOVTilesToSFOVIds(qResolvedTiles.getTileSpecs(), + mFOVName); final String pGroupId = pZ.toString(); final String qGroupId = qZ.toString(); @@ -325,7 +326,7 @@ public void buildUnconnectedData(final Double pZ, } // query web service to find connected tile pairs and remove them from pairs set - if (canvasPairsForMFOV.size() > 0) { + if (! canvasPairsForMFOV.isEmpty()) { for (final CanvasMatches canvasMatches : matchClient.getMatchesBetweenGroups(pGroupId, qGroupId, true)) { @@ -368,7 +369,7 @@ private void storeMatchesForLayer(final Double pZ, mFOVMatches, context); - if (sFOVMatchesList.size() > 0) { + if (! sFOVMatchesList.isEmpty()) { LOG.info("storeMatchesForLayer: saving matches for {}", context); if (parameters.matchStorageFile != null) { @@ -398,7 +399,7 @@ private List buildMatches(final Double pZ, OrderedCanvasIdPair firstUnconnectedPairWithWrongSFOVIndex = null; for (final OrderedCanvasIdPair canvasPair : unconnectedPairsForMFOV) { - final String sFOV = Utilities.getSFOVForTileId(canvasPair.getP().getId()); + final String sFOV = MultiSemUtilities.getSFOVForTileId(canvasPair.getP().getId()); final String sFOVIndex = sFOV.substring(sFOV.length() - 3); if (parameters.sFOVIndexSet.contains(sFOVIndex)) { unconnectedPairsWithSFOVIndex.add(canvasPair); @@ -407,7 +408,7 @@ private List buildMatches(final Double pZ, } } - if (unconnectedPairsWithSFOVIndex.size() == 0) { + if (unconnectedPairsWithSFOVIndex.isEmpty()) { if (firstUnconnectedPairWithWrongSFOVIndex == null) { LOG.warn("buildMatches: no unconnected pairs exist for {}", context); } else { @@ -446,8 +447,8 @@ private CanvasMatches buildMatchesUsingInvertedTransformForSFOVPair(final Double final TileSpec pTileSpec = pResolvedTiles.getTileSpec(p.getId()); final TileSpec qTileSpec = qResolvedTiles.getTileSpec(q.getId()); - final List pPoints = Utilities.transformMFOVMatchesForTile(mFOVMatches, pTileSpec, true); - final List qPoints = Utilities.transformMFOVMatchesForTile(mFOVMatches, qTileSpec, false); + final List pPoints = MultiSemUtilities.transformMFOVMatchesForTile(mFOVMatches, pTileSpec, true); + final List qPoints = MultiSemUtilities.transformMFOVMatchesForTile(mFOVMatches, qTileSpec, false); final List matchList = new ArrayList<>(pPoints.size()); for (int i = 0; i < pPoints.size(); i++) { @@ -458,7 +459,7 @@ private CanvasMatches buildMatchesUsingInvertedTransformForSFOVPair(final Double } } - if (matchList.size() == 0) { + if (matchList.isEmpty()) { throw new IOException("unable to invert matches for sFOV pair " + sFOVPair); } diff --git a/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVMontageMatchPatchClient.java b/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVMontageMatchPatchClient.java index 6a07bcaf4..252dd65e2 100644 --- a/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVMontageMatchPatchClient.java +++ b/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVMontageMatchPatchClient.java @@ -17,6 +17,7 @@ import org.janelia.alignment.match.CanvasMatches; import org.janelia.alignment.match.MatchCollectionId; import org.janelia.alignment.match.OrderedCanvasIdPair; +import org.janelia.alignment.multisem.MultiSemUtilities; import org.janelia.alignment.multisem.StackMFOVWithZValues; import org.janelia.alignment.spec.ResolvedTileSpecCollection; import org.janelia.alignment.spec.TileBounds; @@ -238,6 +239,7 @@ public void updatePositionPairDataForZ(final String stack, null, false, false, + false, false); // add all MFOV tile pairs to unconnected set @@ -285,9 +287,9 @@ public void updatePositionPairDataForZ(final String stack, } } else { // TODO: as coded here, same layer pair will often come from last MFOV (19) - does it matter? - final String sfovIndexPairName = Utilities.getSFOVIndexPairName(canvasMatches.getpGroupId(), - pId, - qId); + final String sfovIndexPairName = MultiSemUtilities.getSFOVIndexPairName(canvasMatches.getpGroupId(), + pId, + qId); sameLayerPairsFromOtherMFOVs.put(sfovIndexPairName, pair); } } @@ -302,9 +304,9 @@ public void updatePositionPairDataForZ(final String stack, // add same layer pair from another MFOV if any exists final CanvasId p = unconnectedPair.getP(); - final String indexPairName = Utilities.getSFOVIndexPairName(p.getGroupId(), - p.getId(), - unconnectedPair.getQ().getId()); + final String indexPairName = MultiSemUtilities.getSFOVIndexPairName(p.getGroupId(), + p.getId(), + unconnectedPair.getQ().getId()); final OrderedCanvasIdPair sameLayerPair = sameLayerPairsFromOtherMFOVs.get(indexPairName); if (sameLayerPair == null) { LOG.info("updatePositionPairDataForZ: no same layer pair found for unconnected pair {}", diff --git a/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVMontageSolverClient.java b/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVMontageSolverClient.java index a4099a3a9..ac7800580 100644 --- a/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVMontageSolverClient.java +++ b/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/MFOVMontageSolverClient.java @@ -16,6 +16,7 @@ import org.janelia.alignment.match.MatchCollectionId; import org.janelia.alignment.match.ModelType; import org.janelia.alignment.multisem.LayerMFOV; +import org.janelia.alignment.multisem.MultiSemUtilities; import org.janelia.alignment.multisem.UnconnectedMFOVPairsForStack; import org.janelia.alignment.spec.ResolvedTileSpecCollection; import org.janelia.alignment.spec.TileSpec; @@ -92,7 +93,7 @@ public void runClient(final String[] args) throws Exception { } public void loadAndSolveUnconnectedMFOVs(final Parameters parameters) throws IOException { - if (parameters.unconnectedMFOVPairsFiles.size() > 0) { + if (! parameters.unconnectedMFOVPairsFiles.isEmpty()) { final ArrayList unconnectedMFOVsForAllStacks = new ArrayList<>( @@ -161,7 +162,7 @@ public static void solveUnconnectedStack(final String baseDataUrl, final Set tileIdsToKeep = resolvedTiles.getTileSpecs() .stream() .map(TileSpec::getTileId) - .filter(id -> mFOVSet.contains(Utilities.getMFOVForTileId(id))) + .filter(id -> mFOVSet.contains(MultiSemUtilities.getMFOVForTileId(id))) .collect(Collectors.toSet()); resolvedTiles.retainTileSpecs(tileIdsToKeep); resolvedTiles.resolveTileSpecs(); @@ -215,8 +216,8 @@ private static Map 0; + return ! unconnectedPairsForPosition.isEmpty(); } public void addSameLayerPair(final OrderedCanvasIdPair sameLayerPair) { @@ -119,7 +120,7 @@ public List deriveMatchesForUnconnectedPairs(final RenderDataClie final List derivedMatchesList = new ArrayList<>(); - if (unconnectedPairsForPosition.size() > 0) { + if (! unconnectedPairsForPosition.isEmpty()) { // if same layer matching is requested, first try to patch with same layer matches final Set unconnectedPairsWithSameLayerSubstitute; @@ -227,8 +228,8 @@ private void deriveMatchesUsingDataFromOtherLayers(final RenderDataClient matchC // AffineModel2D existingMatchModel = new AffineModel2D(); // RigidModel2D existingMatchModel = new RigidModel2D(); final TranslationModel2D existingMatchModel = new TranslationModel2D(); - Utilities.fitModelAndLogStats(existingMatchModel, - canvasMatches, + MultiSemUtilities.fitModelAndLogStats(existingMatchModel, + canvasMatches, "existing pair " + pair); final TileSpec pTileSpec = idToTileSpec.get(p.getId()); @@ -251,7 +252,7 @@ private void deriveMatchesUsingDataFromOtherLayers(final RenderDataClient matchC // TODO: compute errors and display? final AffineModel2D existingCornerMatchModel = new AffineModel2D(); try { - Utilities.fitModelAndLogStats(existingCornerMatchModel, existingCornerMatchList, "corner matches"); + MultiSemUtilities.fitModelAndLogStats(existingCornerMatchModel, existingCornerMatchList, "corner matches"); } catch (final Exception e) { throw new IOException("failed to fit model for corner matches", e); } @@ -268,11 +269,11 @@ private void deriveMatchesUsingDataFromOtherLayers(final RenderDataClient matchC // Note: derivedMatchWeight is included in missingCornerMatchList PointMatch constructor (above) // and then saved with converted canvas matches here derivedMatchesList.add( - Utilities.buildPointMatches(pair, - Utilities.getMatchingTransformedCornersForTile(pTileSpec, cornerMargin), - Utilities.getMatchingTransformedCornersForTile(qTileSpec, cornerMargin), - existingCornerMatchModel, - derivedMatchWeight)); + MultiSemUtilities.buildPointMatches(pair, + MultiSemUtilities.getMatchingTransformedCornersForTile(pTileSpec, cornerMargin), + MultiSemUtilities.getMatchingTransformedCornersForTile(qTileSpec, cornerMargin), + existingCornerMatchModel, + derivedMatchWeight)); addedPairCount++; } } diff --git a/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/UnconnectedCrossMFOVClient.java b/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/UnconnectedCrossMFOVClient.java index 6652818de..7ce4aff53 100644 --- a/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/UnconnectedCrossMFOVClient.java +++ b/render-ws-java-client/src/main/java/org/janelia/render/client/multisem/UnconnectedCrossMFOVClient.java @@ -16,6 +16,7 @@ import org.janelia.alignment.match.CanvasMatches; import org.janelia.alignment.match.MatchCollectionId; import org.janelia.alignment.multisem.LayerMFOV; +import org.janelia.alignment.multisem.MultiSemUtilities; import org.janelia.alignment.multisem.OrderedMFOVPair; import org.janelia.alignment.multisem.UnconnectedMFOVPairsForStack; import org.janelia.alignment.spec.stack.StackId; @@ -182,7 +183,7 @@ public void addUnconnectedMFOVPairsForLayer(final Double pZ, final String pGroupId = String.valueOf(pZ); final String qGroupId = String.valueOf(qZ); - final List mFOVNames = Utilities.getMFOVNames(renderDataClient, stack, pZ); + final List mFOVNames = MultiProjectParameters.getMFOVNames(renderDataClient, stack, pZ); final Map mFOVToSFOVPairCount = new HashMap<>(); mFOVNames.forEach(name -> mFOVToSFOVPairCount.put(name, 0)); @@ -193,8 +194,8 @@ public void addUnconnectedMFOVPairsForLayer(final Double pZ, for (final CanvasMatches canvasMatches : matchClient.getMatchesBetweenGroups(pGroupId, qGroupId, true)) { - final String pMFOVName = Utilities.getMFOVForTileId(canvasMatches.getpId()); - final String qMFOVName = Utilities.getMFOVForTileId(canvasMatches.getqId()); + final String pMFOVName = MultiSemUtilities.getMFOVForTileId(canvasMatches.getpId()); + final String qMFOVName = MultiSemUtilities.getMFOVForTileId(canvasMatches.getqId()); final Integer sFOVPairCount = mFOVToSFOVPairCount.get(pMFOVName); if ((sFOVPairCount != null) && (pMFOVName.equals(qMFOVName))) { mFOVToSFOVPairCount.put(pMFOVName, sFOVPairCount + 1); diff --git a/render-ws-java-client/src/main/java/org/janelia/render/client/parameter/MFOVMontageMatchPatchParameters.java b/render-ws-java-client/src/main/java/org/janelia/render/client/parameter/MFOVMontageMatchPatchParameters.java index a4207953d..cbf686f9e 100644 --- a/render-ws-java-client/src/main/java/org/janelia/render/client/parameter/MFOVMontageMatchPatchParameters.java +++ b/render-ws-java-client/src/main/java/org/janelia/render/client/parameter/MFOVMontageMatchPatchParameters.java @@ -14,7 +14,7 @@ import org.janelia.alignment.match.MatchCollectionId; import org.janelia.alignment.multisem.StackMFOVWithZValues; import org.janelia.alignment.util.FileUtil; -import org.janelia.render.client.multisem.Utilities; +import org.janelia.alignment.multisem.MultiSemUtilities; /** * Parameters for MFOV montage match patching. @@ -128,9 +128,9 @@ public String getMultiFieldOfViewId() { String mFOVId = multiFieldOfViewId; if (mFOVId == null) { if (pTileId != null) { - mFOVId = Utilities.getMFOVForTileId(pTileId); + mFOVId = MultiSemUtilities.getMFOVForTileId(pTileId); } else if (qTileId != null) { - mFOVId = Utilities.getMFOVForTileId(qTileId); + mFOVId = MultiSemUtilities.getMFOVForTileId(qTileId); } } return mFOVId; @@ -184,10 +184,10 @@ private void validateAndSetupDerivedValues() throws IllegalArgumentException { if (pTileId != null) { - multiFieldOfViewId = Utilities.getMFOVForTileId(pTileId); + multiFieldOfViewId = MultiSemUtilities.getMFOVForTileId(pTileId); pTileIdPrefixForRun = getTileIdPrefixForRun(pTileId); if (qTileId != null) { - if (! multiFieldOfViewId.equals(Utilities.getMFOVForTileId(qTileId))) { + if (! multiFieldOfViewId.equals(MultiSemUtilities.getMFOVForTileId(qTileId))) { throw new IllegalArgumentException("pTileId and qTileId reference different MFOVs"); } qTileIdPrefixForRun = getTileIdPrefixForRun(qTileId); @@ -195,7 +195,7 @@ private void validateAndSetupDerivedValues() qTileIdPrefixForRun = multiFieldOfViewId; } } else if (qTileId != null) { - multiFieldOfViewId = Utilities.getMFOVForTileId(qTileId); + multiFieldOfViewId = MultiSemUtilities.getMFOVForTileId(qTileId); qTileIdPrefixForRun = getTileIdPrefixForRun(qTileId); pTileIdPrefixForRun = multiFieldOfViewId; } else if ((multiFieldOfViewId == null) || (multiFieldOfViewId.length() != 10)) { @@ -206,7 +206,7 @@ private void validateAndSetupDerivedValues() } if (matchStorageFile != null) { - Utilities.validateMatchStorageLocation(matchStorageFile); + MultiSemUtilities.validateMatchStorageLocation(matchStorageFile); } } diff --git a/render-ws-java-client/src/main/java/org/janelia/render/client/parameter/MultiProjectParameters.java b/render-ws-java-client/src/main/java/org/janelia/render/client/parameter/MultiProjectParameters.java index d3f5ca7f0..a3396bbc1 100644 --- a/render-ws-java-client/src/main/java/org/janelia/render/client/parameter/MultiProjectParameters.java +++ b/render-ws-java-client/src/main/java/org/janelia/render/client/parameter/MultiProjectParameters.java @@ -9,6 +9,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import org.janelia.alignment.json.JsonUtils; import org.janelia.alignment.match.MatchCollectionId; @@ -17,7 +18,7 @@ import org.janelia.alignment.spec.stack.StackIdNamingGroup; import org.janelia.alignment.spec.stack.StackWithZValues; import org.janelia.render.client.RenderDataClient; -import org.janelia.render.client.multisem.Utilities; +import org.janelia.alignment.multisem.MultiSemUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -113,9 +114,9 @@ public List buildListOfStackMFOVWithAllZ(final String mult final StackId stackId = stackWithZValues.getStackId(); final RenderDataClient dataClient = defaultRenderClient.buildClient(stackId.getOwner(), stackId.getProject()); - final List mFOVIdList = Utilities.getMFOVNames(dataClient, - stackId.getStack(), - stackWithZValues.getFirstZ()); + final List mFOVIdList = getMFOVNames(dataClient, + stackId.getStack(), + stackWithZValues.getFirstZ()); LOG.info("buildListOfStackMFOVWithAllZ: found {} MFOVs in {}", mFOVIdList.size(), stackWithZValues); @@ -153,4 +154,19 @@ private synchronized void buildDataClient() { private static final JsonUtils.Helper JSON_HELPER = new JsonUtils.Helper<>(MultiProjectParameters.class); + /** + * @return list of distinct sorted MFOV names for the specified stack z-layer. + */ + public static List getMFOVNames(final RenderDataClient renderDataClient, + final String stack, + final Double z) + throws IOException { + return renderDataClient.getTileBounds(stack, z) + .stream() + .map(tileBounds -> MultiSemUtilities.getMFOVForTileId(tileBounds.getTileId())) + .distinct() + .sorted() + .collect(Collectors.toList()); + } + } \ No newline at end of file diff --git a/render-ws-java-client/src/test/java/org/janelia/render/client/multisem/UtilitiesTest.java b/render-ws-java-client/src/test/java/org/janelia/render/client/multisem/UtilitiesTest.java deleted file mode 100644 index 346ef06e2..000000000 --- a/render-ws-java-client/src/test/java/org/janelia/render/client/multisem/UtilitiesTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.janelia.render.client.multisem; - -import org.junit.Assert; -import org.junit.Test; - -/** - * Tests the {@link Utilities} class. - * - * @author Eric Trautman - */ -public class UtilitiesTest { - - @Test - public void testTileIdParsers() { - final String tileId = "w60_magc0399_scan005_m0013_s001"; - Assert.assertEquals("invalid MFOVForTileId", - "0399_m0013", Utilities.getMFOVForTileId(tileId)); - Assert.assertEquals("invalid SFOVForTileId", - "0399_m0013_s001", Utilities.getSFOVForTileId(tileId)); - Assert.assertEquals("invalid SFOVIndexForTileId", - "001", Utilities.getSFOVIndexForTileId(tileId)); - } - -}