diff --git a/render-ws/src/main/java/org/janelia/render/service/TileDataService.java b/render-ws/src/main/java/org/janelia/render/service/TileDataService.java index 5137e93b9..4c7439c4c 100644 --- a/render-ws/src/main/java/org/janelia/render/service/TileDataService.java +++ b/render-ws/src/main/java/org/janelia/render/service/TileDataService.java @@ -142,80 +142,13 @@ public RenderParameters getRenderParameters(@PathParam("owner") final String own RenderParameters parameters = null; try { - final TileSpec tileSpec = getTileSpec(owner, project, stack, tileId, true); - tileSpec.flattenTransforms(); - - double tileRenderX = tileSpec.getMinX(); - double tileRenderY = tileSpec.getMinY(); - - int tileRenderWidth; - if (width == null) { - tileRenderWidth = (int) (tileSpec.getMaxX() - tileSpec.getMinX()); - } else { - tileRenderWidth = width; - } - - int tileRenderHeight; - if (height == null) { - tileRenderHeight = (int) (tileSpec.getMaxY() - tileSpec.getMinY()); - } else { - tileRenderHeight = height; - } - final StackId stackId = new StackId(owner, project, stack); final StackMetaData stackMetaData = getStackMetaData(stackId); - if ((normalizeForMatching != null) && normalizeForMatching) { - - // When deriving point matches for a tile pair in which each tile has different lens correction - // transformations, the bounding box for each rendered tile needs to be normalized. - // - // Normalization is achieved by: - // (1) Removing the last transform spec (assumed to be an affine that positions the tile in the world). - // (2) Setting the render start coordinate to (0,0). - // (3) Padding the raw tile width and height by multiplying a normalization factor (1.05). - // Assuming that all tiles in a stack have the same raw width and height, this ensures - // that normalized tiles also have the same width and height with a little extra room - // for edges that are rotated/skewed by lens correction. - // (4) Ensuring that the normalized width and height are even by adding a pixel as needed. - // - // Consistent and even tile sizes are currently a requirement for generating DMesh point matches. - - final double normalizationFactor = 1.05; - if (width == null) { - tileRenderWidth = (int) (tileSpec.getWidth() * normalizationFactor); - } - if (height == null) { - tileRenderHeight = (int) (tileSpec.getHeight() * normalizationFactor); - } - - tileSpec.removeLastTransformSpec(); + final TileSpec tileSpec = getTileSpec(owner, project, stack, tileId, true); - // If the tile still has more than 3 transforms, remove all but the last 3. - // This assumes that the last 3 transforms are for lens correction. - // Hopefully at some point we'll label transforms so that it is possible to - // explicitly include only lens correction transforms. - while (tileSpec.getTransforms().size() > 3) { - tileSpec.removeLastTransformSpec(); - } - - tileRenderX = 0; - tileRenderY = 0; - - if ((tileRenderWidth % 2) == 1) { - tileRenderWidth++; - } - if ((tileRenderHeight % 2) == 1) { - tileRenderHeight++; - } - } + parameters = getCoreTileRenderParameters(width, height, scale, normalizeForMatching, tileSpec); - parameters = new RenderParameters(null, - tileRenderX, - tileRenderY, - tileRenderWidth, - tileRenderHeight, - scale); parameters.setDoFilter(filter); parameters.setBinaryMask(binaryMask); parameters.setExcludeMask(excludeMask); @@ -340,6 +273,78 @@ public RenderParameters getTileWithNeighborsRenderParameters(@PathParam("owner") return parameters; } + protected static RenderParameters getCoreTileRenderParameters(final Integer width, + final Integer height, + final Double scale, + final Boolean normalizeForMatching, + final TileSpec tileSpec) { + tileSpec.flattenTransforms(); + + double tileRenderX = tileSpec.getMinX(); + double tileRenderY = tileSpec.getMinY(); + + int tileRenderWidth; + if (width == null) { + tileRenderWidth = (int) (tileSpec.getMaxX() - tileSpec.getMinX() + 1); + } else { + tileRenderWidth = width; + } + + int tileRenderHeight; + if (height == null) { + tileRenderHeight = (int) (tileSpec.getMaxY() - tileSpec.getMinY() + 1); + } else { + tileRenderHeight = height; + } + + if ((normalizeForMatching != null) && normalizeForMatching) { + + // When deriving point matches for a tile pair in which each tile has different lens correction + // transformations, the bounding box for each rendered tile needs to be normalized. + // + // Normalization is achieved by: + // (1) Removing the last transform spec (assumed to be an affine that positions the tile in the world). + // (2) Setting the render start coordinate to (0,0). + // (3) Padding the raw tile width and height by multiplying a normalization factor (1.05). + // Assuming that all tiles in a stack have the same raw width and height, this ensures + // that normalized tiles also have the same width and height with a little extra room + // for edges that are rotated/skewed by lens correction. + // (4) Ensuring that the normalized width and height are even by adding a pixel as needed. + // + // Consistent and even tile sizes are currently a requirement for generating DMesh point matches. + + final double normalizationFactor = 1.05; + if (width == null) { + tileRenderWidth = (int) (tileSpec.getWidth() * normalizationFactor); + } + if (height == null) { + tileRenderHeight = (int) (tileSpec.getHeight() * normalizationFactor); + } + + tileSpec.removeLastTransformSpec(); + + // If the tile still has more than 3 transforms, remove all but the last 3. + // This assumes that the last 3 transforms are for lens correction. + // Hopefully at some point we'll label transforms so that it is possible to + // explicitly include only lens correction transforms. + while (tileSpec.getTransforms().size() > 3) { + tileSpec.removeLastTransformSpec(); + } + + tileRenderX = 0; + tileRenderY = 0; + + if ((tileRenderWidth % 2) == 1) { + tileRenderWidth++; + } + if ((tileRenderHeight % 2) == 1) { + tileRenderHeight++; + } + } + + return new RenderParameters(null, tileRenderX, tileRenderY, tileRenderWidth, tileRenderHeight, scale); + } + private StackMetaData getStackMetaData(final StackId stackId) throws ObjectNotFoundException { diff --git a/render-ws/src/test/java/org/janelia/render/service/TileDataServiceTest.java b/render-ws/src/test/java/org/janelia/render/service/TileDataServiceTest.java new file mode 100644 index 000000000..8f6139db7 --- /dev/null +++ b/render-ws/src/test/java/org/janelia/render/service/TileDataServiceTest.java @@ -0,0 +1,49 @@ +package org.janelia.render.service; + +import org.janelia.alignment.RenderParameters; +import org.janelia.alignment.spec.TileSpec; +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests the {@link TileDataService} class. + * + * @author Eric Trautman + */ +public class TileDataServiceTest { + + @Test + public void testGetCoreTileRenderParameters() throws Exception { + + final String json = + "{\n" + + " \"tileId\" : \"1,3484_aligned_0_1_flip\",\n" + + " \"z\" : 3484.0, \"minX\" : 1896.0, \"minY\" : 876.0, \"maxX\" : 2919.0, \"maxY\" : 1899.0,\n" + + " \"width\" : 1024.0, \"height\" : 1024.0,\n" + + " \"mipmapLevels\" : {\n" + + " \"0\" : {\n" + + " \"imageUrl\" : \"file:///data/nc-em/russelt/20170227_Princeton_Pinky40/4_aligned_tiled/1,3484_aligned_0_1_flip.png\"\n" + + " }\n" + + " },\n" + + " \"transforms\" : {\n" + + " \"type\" : \"list\",\n" + + " \"specList\" : [ {\n" + + " \"className\" : \"mpicbg.trakem2.transform.AffineModel2D\",\n" + + " \"dataString\" : \"1.0000000000 0.0000000000 0.0000000000 1.0000000000 1896.0000000000 -876.0000000000\"\n" + + " }, {\n" + + " \"className\" : \"mpicbg.trakem2.transform.AffineModel2D\",\n" + + " \"dataString\" : \"1.0000000000 0.0000000000 0.0000000000 1.0000000000 0.0000000000 1752.0000000000\"\n" + + " } ]\n" + + " }\n" + + "}"; + + final TileSpec tileSpec = TileSpec.fromJson(json); + + final RenderParameters renderParameters = + TileDataService.getCoreTileRenderParameters(null, null, null, null, tileSpec); + + Assert.assertEquals("invalid width for tile", 1024, renderParameters.getWidth()); + Assert.assertEquals("invalid height for tile", 1024, renderParameters.getHeight()); + } + +}