From 92f6e0f8a856be68c81f535505c6b3a63e04c850 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Fri, 2 Oct 2015 15:22:15 -0400 Subject: [PATCH 01/35] Changes to support the scaling a certain region specified by start/end column and start/end row --- .../CATMAIDRandomAccessibleInterval.java | 9 +- src/main/java/org/catmaid/Downsampler.java | 13 +- src/main/java/org/catmaid/ScaleCATMAID.java | 158 ++++++++++-------- src/main/java/org/catmaid/TileCATMAID.java | 16 +- src/main/java/org/catmaid/Tiler.java | 47 +----- 5 files changed, 114 insertions(+), 129 deletions(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index 72002eb..6801dc2 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -663,16 +663,15 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) if ( cachedEntry != null ) return cachedEntry.data; } - + final String urlString = String.format( urlFormat, s, scale, c * tileWidth, r * tileHeight, z, tileWidth, tileHeight, r, c ); final int[] pixels = new int[ tileWidth * tileHeight ]; try { final URL url = new URL( urlString ); -// final Image image = toolkit.createImage( url ); - final BufferedImage jpg = ImageIO.read( url ); - + final BufferedImage jpg = ImageIO.read( url ); + /* This gymnastic is necessary to get reproducible gray * values, just opening a JPG or PNG, even when saved by * ImageIO, and grabbing its pixels results in gray values @@ -682,7 +681,7 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) image.createGraphics().drawImage( jpg, 0, 0, null ); final PixelGrabber pg = new PixelGrabber( image, 0, 0, tileWidth, tileHeight, pixels, 0, tileWidth ); pg.grabPixels(); - + cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) ); // System.out.println( "success loading r=" + r + " c=" + c + " url(" + urlString + ")" ); diff --git a/src/main/java/org/catmaid/Downsampler.java b/src/main/java/org/catmaid/Downsampler.java index 49e29f9..7b248ae 100644 --- a/src/main/java/org/catmaid/Downsampler.java +++ b/src/main/java/org/catmaid/Downsampler.java @@ -98,8 +98,8 @@ final static public void downsampleBytes( final byte[] aPixels, final byte[] bPi } } } - - final static public void downsampleRGB( final int[] aPixels, final int[] bPixels, final int wa, final int ha ) + + final static public boolean downsampleRGB( final int[] aPixels, final int[] bPixels, final int wa, final int ha ) { assert aPixels.length == wa * ha && bPixels.length == wa / 2 * ( ha / 2 ) : "Input dimensions do not match."; @@ -108,15 +108,20 @@ final static public void downsampleRGB( final int[] aPixels, final int[] bPixels final int wb = wa / 2; final int hb = ha / 2; final int nb = hb * wb; - + boolean bresult = false; for ( int ya = 0, yb = 0; yb < nb; ya += wa2, yb += wb ) { final int ya1 = ya + wa; for ( int xa = 0, xb = 0; xb < wb; xa += 2, ++xb ) { final int xa1 = xa + 1; - bPixels[ yb + xb ] = averageColor( ya + xa, ya + xa1, ya1 + xa, ya1 + xa1, aPixels ); + int c = averageColor( ya + xa, ya + xa1, ya1 + xa, ya1 + xa1, aPixels ); + bPixels[ yb + xb ] = c; + if ((c & 0xFFFFFF) != 0) { + bresult = true; // return true since at least one pixel is non black + } } } + return bresult; } } diff --git a/src/main/java/org/catmaid/ScaleCATMAID.java b/src/main/java/org/catmaid/ScaleCATMAID.java index 07ee868..cc77dfd 100644 --- a/src/main/java/org/catmaid/ScaleCATMAID.java +++ b/src/main/java/org/catmaid/ScaleCATMAID.java @@ -72,46 +72,55 @@ static protected class Param { public int tileWidth; public int tileHeight; + public long minC; + public long maxC; + public long minR; + public long maxR; public long minZ; public long maxZ; public String tileFormat; public String format; public float quality; public int type; + public boolean ignoreEmptyTiles; } - - private ScaleCATMAID(){} - - static protected Param parseParameters() - { + + private ScaleCATMAID() {} + + static protected Param parseParameters() { final Param p = new Param(); p.tileWidth = Integer.parseInt( System.getProperty( "tileWidth", "256" ) ); p.tileHeight = Integer.parseInt( System.getProperty( "tileHeight", "256" ) ); - + + p.minC = Long.parseLong( System.getProperty( "minC", "0" ) ); + p.maxC = Long.parseLong( System.getProperty( "maxC", "" + Integer.MAX_VALUE ) ); + p.minR = Long.parseLong( System.getProperty( "minR", "0" ) ); + p.maxR = Long.parseLong( System.getProperty( "maxR", "" + Integer.MAX_VALUE ) ); p.minZ = Long.parseLong( System.getProperty( "minZ", "0" ) ); p.maxZ = Long.parseLong( System.getProperty( "maxZ", "" + Long.MAX_VALUE ) ); final String basePath = System.getProperty( "basePath", "" ); - p.tileFormat = System.getProperty( "tileFormat", basePath + "%5$d/%8$d_%9$d_%1$d.jpg" ); - - System.out.println( p.tileFormat ); - p.format = System.getProperty( "format", "jpg" ); + final String tileFormat = System.getProperty( "tileFormat", "%5$d/%8$d_%9$d_%1$d"); + p.tileFormat = basePath + "/" + tileFormat + "." + p.format; + + System.out.println("Tile pattern: " + p.tileFormat ); + p.quality = Float.parseFloat( System.getProperty( "quality", "0.85" ) ); final String type = System.getProperty( "type", "rgb" ); if ( type.equalsIgnoreCase( "gray" ) || type.equalsIgnoreCase( "grey" ) ) p.type = BufferedImage.TYPE_BYTE_GRAY; else p.type = BufferedImage.TYPE_INT_RGB; - + p.ignoreEmptyTiles = Boolean.valueOf(System.getProperty( "ignoreEmptyTiles")); + return p; } - + final static protected BufferedImage open( final String path, final BufferedImage alternative, final int type ) { -// System.out.println( path ); final File file = new File( path ); if ( file.exists() ) { @@ -127,13 +136,12 @@ final static protected BufferedImage open( else return alternative; } - - + /** * Generate scaled tiles from a range of an existing scale level 0 tile * stack. * - * @param tileFormat format string adfdressing tiles including basePath + * @param tileFormat format string addressing tiles including basePath * @param tileWidth * @param tileHeight * @param minZ the first z-index to be scaled @@ -142,6 +150,7 @@ final static protected BufferedImage open( * @param quality quality for jpg-compression if format is "jpg" * @param type the type of export tiles, e.g. * {@link BufferedImage#TYPE_BYTE_GRAY} + * @param ignoreEmptyTiles - if true don't save empty tiles * * @throws Exception */ @@ -149,113 +158,118 @@ final public static void scale( final String tileFormat, final int tileWidth, final int tileHeight, + final long minX, + final long maxX, + final long minY, + final long maxY, final long minZ, final long maxZ, final String format, final float quality, - final int type ) throws Exception + final int type, + final boolean ignoreEmptyTiles) throws Exception { final BufferedImage alternative = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); - + final int[] targetPixels = new int[ tileWidth * tileHeight ]; final BufferedImage target = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); final BufferedImage sourceImage = new BufferedImage( tileWidth * 2, tileHeight * 2, BufferedImage.TYPE_INT_RGB ); final Graphics2D g = sourceImage.createGraphics(); final int[] sourcePixels = new int[ tileWidth * tileHeight * 4 ]; - -Z: for ( long z = minZ; z <= maxZ; ++z ) + + for ( long z = minZ; z <= maxZ; z++ ) { System.out.println( "z-index: " + z ); -S: for ( int s = 1; true; ++s ) + boolean workToDo = true; + for ( int s = 1; workToDo; ++s ) { - System.out.println( " scale: " + s ); + System.out.println( "scale: " + s ); final int iScale = 1 << s; final double scale = 1.0 / iScale; - + final int s1 = s - 1; final int iScale1 = 1 << s1; final double scale1 = 1.0 / iScale1; - - boolean proceedY = true; -Y: for ( long y = 0; proceedY; y += tileHeight ) + int nResultTiles = 0; + + workToDo = false; + for ( long y = minY / iScale1; y < maxY / iScale1; y += 2 * tileHeight ) { - final long yt = y / tileHeight; - boolean proceedX = true; - for ( long x = 0; proceedX; x += tileWidth ) + workToDo = true; + final long yt = y / (2 * tileHeight); + for ( long x = minX / iScale1; x < maxX / iScale1; x += 2 * tileWidth ) { - final long xt = x / tileWidth; + nResultTiles++; + final long xt = x / (2 * tileWidth); final Image imp1 = open( String.format( tileFormat, s1, scale1, x * iScale1, y * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt, 2 * xt ), alternative, type ); - if ( imp1 == alternative ) - if ( x == 0 ) - if ( y == 0 ) - break Z; - else - continue S; - else - continue Y; - final Image imp2 = open( String.format( tileFormat, s1, scale1, ( x + tileWidth ) * iScale1, y * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt, 2 * xt + 1 ), alternative, type ); - - proceedX = imp2 != alternative; - + final Image imp3 = open( String.format( tileFormat, s1, scale1, x * iScale1, ( y + tileHeight ) * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt + 1, 2 * xt ), alternative, type ); - - proceedY = imp3 != alternative; - - if ( x == 0 && y == 0 && !( proceedX || proceedY) ) - break S; - + final Image imp4 = open( String.format( tileFormat, s1, scale1, ( x + tileWidth ) * iScale1, ( y + tileHeight ) * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt + 1, 2 * xt + 1 ), alternative, type ); - + + if (imp1 == alternative && imp2 == alternative && imp3 == alternative && imp4 == alternative) { + continue; + } + g.drawImage( imp1, 0, 0, null ); g.drawImage( imp2, tileWidth, 0, null ); g.drawImage( imp3, 0, tileHeight, null ); g.drawImage( imp4, tileWidth, tileHeight, null ); - + final PixelGrabber pg = new PixelGrabber( sourceImage, 0, 0, tileWidth * 2, tileHeight * 2, sourcePixels, 0, tileWidth * 2 ); pg.grabPixels(); - - Downsampler.downsampleRGB( sourcePixels, targetPixels, tileWidth * 2, tileHeight * 2 ); - - target.getRaster().setDataElements( 0, 0, tileWidth, tileHeight, targetPixels ); - final BufferedImage targetCopy = Util.draw( target, type ); - Util.writeTile( - targetCopy, - String.format( tileFormat, s, scale, x * iScale, y * iScale, z, tileWidth * iScale, tileHeight * iScale, yt, xt ), - format, - quality ); - } + boolean notEmpty = Downsampler.downsampleRGB( sourcePixels, targetPixels, tileWidth * 2, tileHeight * 2 ); + + if (notEmpty || !ignoreEmptyTiles) { + target.getRaster().setDataElements( 0, 0, tileWidth, tileHeight, targetPixels ); + final BufferedImage targetCopy = Util.draw( target, type ); + + Util.writeTile( + targetCopy, + String.format( tileFormat, s, scale, x * iScale, y * iScale, z, tileWidth * iScale, tileHeight * iScale, yt, xt ), + format, + quality ); + } + } // end for x + } // end for y + if (nResultTiles <= 1) { + workToDo = false; } - } - } + } // end for s + } // end for z } final static public void scale( final Param p ) throws Exception { - scale( - p.tileFormat, - p.tileWidth, - p.tileHeight, - p.minZ, - p.maxZ, - p.format, - p.quality, - p.type ); + scale(p.tileFormat, + p.tileWidth, + p.tileHeight, + p.minC * p.tileWidth, + (p.maxC + 1) * p.tileWidth, // include maxC + p.minR * p.tileHeight, + (p.maxR + 1) * p.tileHeight, // include maxR + p.minZ, + p.maxZ, + p.format, + p.quality, + p.type, + p.ignoreEmptyTiles); } diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index 476b45e..c5fa25d 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -184,21 +184,21 @@ static protected Param parseParameters() /* CATMAID source stack */ final String sourceBaseUrl = System.getProperty( "sourceBaseUrl", "" ); p.sourceUrlFormat = System.getProperty( "sourceUrlFormat", sourceBaseUrl + "%5$d/%8$d_%9$d_%1$d.jpg" ); - + p.sourceWidth = Long.parseLong( System.getProperty( "sourceWidth", "0" ) ); p.sourceHeight = Long.parseLong( System.getProperty( "sourceHeight", "0" ) ); p.sourceDepth = Long.parseLong( System.getProperty( "sourceDepth", "0" ) ); p.sourceScaleLevel = Long.parseLong( System.getProperty( "sourceScaleLevel", "0" ) ); - + final int scaleXYDiv = 1 << p.sourceScaleLevel; - + p.sourceTileWidth = Integer.parseInt( System.getProperty( "sourceTileWidth", "256" ) ); p.sourceTileHeight = Integer.parseInt( System.getProperty( "sourceTileHeight", "256" ) ); p.sourceResXY = Double.parseDouble( System.getProperty( "sourceResXY", "1.0" ) ); p.sourceResZ = Double.parseDouble( System.getProperty( "sourceResZ", "1.0" ) ); - + final double scaleZDiv = scaleXYDiv * p.sourceResXY / p.sourceResZ; - + /* export */ final long minX = Long.parseLong( System.getProperty( "minX", "0" ) ); final long minY = Long.parseLong( System.getProperty( "minY", "0" ) ); @@ -235,7 +235,7 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) p.sourceInterval.dimension( 1 ) / scaleXYDiv, ( long )( p.sourceInterval.dimension( 2 ) / scaleZDiv ) ); } - + p.tileWidth = Integer.parseInt( System.getProperty( "tileWidth", "256" ) ); p.tileHeight = Integer.parseInt( System.getProperty( "tileHeight", "256" ) ); p.minZ = Long.parseLong( System.getProperty( "exportMinZ", "0" ) ); @@ -250,9 +250,9 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) p.maxC = Long.parseLong( System.getProperty( "exportMaxC", Long.toString( ( long )Math.ceil( ( double )orientedSourceInterval.dimension( 0 ) / ( double )p.tileWidth ) - 1 ) ) ); - + p.exportPath = System.getProperty( "exportBasePath", "" ); - p.tilePattern = System.getProperty( "tilePattern", "/__" ); + p.tilePattern = System.getProperty( "tilePattern", "%5$d/%8$d_%9$d_%1$d" ); // default is z/row_col_scale p.format = System.getProperty( "format", "jpg" ); p.quality = Float.parseFloat( System.getProperty( "quality", "0.85" ) ); final String type = System.getProperty( "type", "rgb" ); diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java index e8b94f2..9f1d225 100644 --- a/src/main/java/org/catmaid/Tiler.java +++ b/src/main/java/org/catmaid/Tiler.java @@ -38,7 +38,6 @@ */ public class Tiler { -// final static protected Toolkit toolkit = Toolkit.getDefaultToolkit(); final protected RandomAccessibleInterval< ARGBType > source; @@ -117,33 +116,7 @@ final static protected void copyTile( copyTile( raiSource, raiTarget ); } - - - /** - * Replace the ctile coordinates in a pattern string. - * - * @param template - * @param s scale-index (scale = 1/2s) - * @param z z-index - * @param r row - * @param c column - * @return - */ - final static protected String tileName( - final String template, - final long s, - final long z, - final long r, - final long c ) - { - return template. - replace( "", Long.toString( s ) ). - replace( "", Long.toString( z ) ). - replace( "", Long.toString( r ) ). - replace( "", Long.toString( c ) ); - } - - + /** * Generate a subset of a CATMAID tile stack of an {@link Interval} of the * source {@link RandomAccessibleInterval}. That is you can choose the @@ -238,17 +211,15 @@ public void tile( copyTile( sourceTile, tile, orientation == Orientation.ZY, new ARGBType( 0 ) ); img.getRaster().setDataElements( 0, 0, tileWidth, tileHeight, tilePixels ); final BufferedImage imgCopy = Util.draw( img, type ); - final String tilePath = - new StringBuffer( exportPath ). - append( "/" ). - append( tileName( tilePattern, 0, z, r, c ) ). - append( "." ). - append( format ). - toString(); + new StringBuffer(exportPath) + .append( "/" ) + .append(String.format(tilePattern, 0, 1.0, min[0], min[1], z, tileWidth, tileHeight, r, c)) + .append( "." ) + .append( format ) + .toString(); Util.writeTile( imgCopy, tilePath, format, quality ); -// writePngTile( img, sectionPath + "/" + r + "_" + c + "_0.png" ); } } } @@ -306,10 +277,6 @@ public void tile( maxZ = sourceInterval.dimension( 2 ) - 1; } -// System.out.println( "maxZ:" + maxZ ); -// System.out.println( "maxR:" + maxR ); -// System.out.println( "maxC:" + maxC ); - tile( sourceInterval, orientation, From 6f7700c083b6c5fe464c249fc5b40b1768af3e14 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Fri, 2 Oct 2015 18:53:41 -0400 Subject: [PATCH 02/35] fixed the z increment --- src/main/java/org/catmaid/ScaleCATMAID.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/catmaid/ScaleCATMAID.java b/src/main/java/org/catmaid/ScaleCATMAID.java index cc77dfd..c0ef5b4 100644 --- a/src/main/java/org/catmaid/ScaleCATMAID.java +++ b/src/main/java/org/catmaid/ScaleCATMAID.java @@ -178,7 +178,7 @@ final public static void scale( final Graphics2D g = sourceImage.createGraphics(); final int[] sourcePixels = new int[ tileWidth * tileHeight * 4 ]; - for ( long z = minZ; z <= maxZ; z++ ) + for ( long z = minZ; z <= maxZ; ++z ) { System.out.println( "z-index: " + z ); boolean workToDo = true; From 296f0ee135f77db777005cb076d2f2e704d21188 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Fri, 2 Oct 2015 19:44:41 -0400 Subject: [PATCH 03/35] restored the tile format --- src/main/java/org/catmaid/ScaleCATMAID.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/catmaid/ScaleCATMAID.java b/src/main/java/org/catmaid/ScaleCATMAID.java index c0ef5b4..fdebffe 100644 --- a/src/main/java/org/catmaid/ScaleCATMAID.java +++ b/src/main/java/org/catmaid/ScaleCATMAID.java @@ -100,8 +100,7 @@ static protected Param parseParameters() { p.maxZ = Long.parseLong( System.getProperty( "maxZ", "" + Long.MAX_VALUE ) ); final String basePath = System.getProperty( "basePath", "" ); p.format = System.getProperty( "format", "jpg" ); - final String tileFormat = System.getProperty( "tileFormat", "%5$d/%8$d_%9$d_%1$d"); - p.tileFormat = basePath + "/" + tileFormat + "." + p.format; + p.tileFormat = System.getProperty( "tileFormat", basePath + "%5$d/%8$d_%9$d_%1$d" + "." + p.format); System.out.println("Tile pattern: " + p.tileFormat ); From 2e817a6569a1ff97e4ef16871cafb9f472965fcf Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Tue, 6 Oct 2015 09:06:43 -0400 Subject: [PATCH 04/35] Changed the scaler to work both with and without region boundaries --- .gitignore | 5 +- src/main/java/org/catmaid/ScaleCATMAID.java | 99 ++++++++++++++++----- 2 files changed, 80 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index acd1ac3..b1fad23 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ *.jar *.war *.ear -/target +target +.classpath +.project +.settings diff --git a/src/main/java/org/catmaid/ScaleCATMAID.java b/src/main/java/org/catmaid/ScaleCATMAID.java index fdebffe..97cfe59 100644 --- a/src/main/java/org/catmaid/ScaleCATMAID.java +++ b/src/main/java/org/catmaid/ScaleCATMAID.java @@ -72,10 +72,10 @@ static protected class Param { public int tileWidth; public int tileHeight; - public long minC; - public long maxC; - public long minR; - public long maxR; + public long minX; + public long width; + public long minY; + public long height; public long minZ; public long maxZ; public String tileFormat; @@ -92,10 +92,10 @@ static protected Param parseParameters() { p.tileWidth = Integer.parseInt( System.getProperty( "tileWidth", "256" ) ); p.tileHeight = Integer.parseInt( System.getProperty( "tileHeight", "256" ) ); - p.minC = Long.parseLong( System.getProperty( "minC", "0" ) ); - p.maxC = Long.parseLong( System.getProperty( "maxC", "" + Integer.MAX_VALUE ) ); - p.minR = Long.parseLong( System.getProperty( "minR", "0" ) ); - p.maxR = Long.parseLong( System.getProperty( "maxR", "" + Integer.MAX_VALUE ) ); + p.minX = Long.parseLong( System.getProperty( "minX", "0" ) ); + p.width = Long.parseLong( System.getProperty( "width", "-1") ); + p.minY = Long.parseLong( System.getProperty( "minY", "0" ) ); + p.height = Long.parseLong( System.getProperty( "height", "-1" ) ); p.minZ = Long.parseLong( System.getProperty( "minZ", "0" ) ); p.maxZ = Long.parseLong( System.getProperty( "maxZ", "" + Long.MAX_VALUE ) ); final String basePath = System.getProperty( "basePath", "" ); @@ -111,6 +111,18 @@ static protected Param parseParameters() { else p.type = BufferedImage.TYPE_INT_RGB; p.ignoreEmptyTiles = Boolean.valueOf(System.getProperty( "ignoreEmptyTiles")); + if (p.ignoreEmptyTiles) { + if (p.width < 0) { + throw new IllegalArgumentException("Width must be defined when empty files are not generated"); + } else if (p.minX + p.width < 0) { + throw new IllegalArgumentException("Max X value overflow"); + } + if (p.height < 0) { + throw new IllegalArgumentException("Height must be defined when empty files are not generated"); + } else if (p.minY + p.height < 0) { + throw new IllegalArgumentException("Max Y value overflow"); + } + } return p; } @@ -120,9 +132,11 @@ final static protected BufferedImage open( final BufferedImage alternative, final int type ) { + System.out.println("Read " + path); final File file = new File( path ); if ( file.exists() ) { + System.out.println("Found " + path); try { return ImageIO.read( new File( path ) ); @@ -158,9 +172,9 @@ final public static void scale( final int tileWidth, final int tileHeight, final long minX, - final long maxX, + final long width, final long minY, - final long maxY, + final long height, final long minZ, final long maxZ, final String format, @@ -177,11 +191,14 @@ final public static void scale( final Graphics2D g = sourceImage.createGraphics(); final int[] sourcePixels = new int[ tileWidth * tileHeight * 4 ]; - for ( long z = minZ; z <= maxZ; ++z ) + final long maxY = height > 0 ? minY + height : -1; + final long maxX = width > 0 ? minX + width : -1; +Z: for ( long z = minZ; z <= maxZ; ++z ) { System.out.println( "z-index: " + z ); - boolean workToDo = true; - for ( int s = 1; workToDo; ++s ) + boolean proceedY = true; + boolean proceedX = true; +S: for ( int s = 1; proceedX || proceedY; ++s ) { System.out.println( "scale: " + s ); final int iScale = 1 << s; @@ -192,13 +209,19 @@ final public static void scale( final double scale1 = 1.0 / iScale1; int nResultTiles = 0; - workToDo = false; - for ( long y = minY / iScale1; y < maxY / iScale1; y += 2 * tileHeight ) + proceedY = true; +Y: for ( long y = minY / iScale1; proceedY; y += 2 * tileHeight ) { - workToDo = true; + if (maxY > 0 && y >= maxY / iScale1) { + break; + } + proceedX = true; final long yt = y / (2 * tileHeight); - for ( long x = minX / iScale1; x < maxX / iScale1; x += 2 * tileWidth ) + for ( long x = minX / iScale1; proceedX; x += 2 * tileWidth ) { + if (maxX > 0 && x >= maxX / iScale1) { + break; + } nResultTiles++; final long xt = x / (2 * tileWidth); final Image imp1 = open( @@ -206,16 +229,34 @@ final public static void scale( alternative, type ); + if (maxX < 0) { + if (imp1 == alternative) { + if ( x == minX / iScale1 ) + if ( y == minY / iScale1 ) + break Z; + else + continue S; + else + continue Y; + } + } final Image imp2 = open( String.format( tileFormat, s1, scale1, ( x + tileWidth ) * iScale1, y * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt, 2 * xt + 1 ), alternative, type ); + proceedX = maxX >= 0 || imp2 != alternative; + final Image imp3 = open( String.format( tileFormat, s1, scale1, x * iScale1, ( y + tileHeight ) * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt + 1, 2 * xt ), alternative, type ); + proceedY = maxY >= 0 || imp3 != alternative; + + if (!proceedX && !proceedY && x == minX / iScale1 && y == minY / iScale1) { + break S; + } final Image imp4 = open( String.format( tileFormat, s1, scale1, ( x + tileWidth ) * iScale1, ( y + tileHeight ) * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt + 1, 2 * xt + 1 ), alternative, @@ -248,7 +289,8 @@ final public static void scale( } // end for x } // end for y if (nResultTiles <= 1) { - workToDo = false; + proceedX = false; + proceedY = false; } } // end for s } // end for z @@ -259,10 +301,10 @@ final static public void scale( final Param p ) throws Exception scale(p.tileFormat, p.tileWidth, p.tileHeight, - p.minC * p.tileWidth, - (p.maxC + 1) * p.tileWidth, // include maxC - p.minR * p.tileHeight, - (p.maxR + 1) * p.tileHeight, // include maxR + adjustStart(p.minX, p.tileWidth), + adjustSize(p.width, p.tileWidth), + adjustStart(p.minY, p.tileHeight), + adjustSize(p.height, p.tileHeight), p.minZ, p.maxZ, p.format, @@ -271,7 +313,18 @@ final static public void scale( final Param p ) throws Exception p.ignoreEmptyTiles); } - + private static final long adjustStart(long index, int tileSize) { + return index / tileSize * tileSize; // make it the start of the corresponding tile + } + + private static final long adjustSize(long size, int tileSize) { + if (size > 0 && size % tileSize > 0) { + return size + tileSize - (size % tileSize); // make it the end of the corresponding tile + } else { + return size; + } + } + final static public void main( final String... args ) throws Exception { scale( parseParameters() ); From 1a548579bd2372135d80e6d09f867bad44f7a1c5 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Tue, 6 Oct 2015 12:48:45 -0400 Subject: [PATCH 05/35] do not append the extension in the code - let the user specify that in the tiler pattern to be consistent with the scaler --- src/main/java/org/catmaid/TileCATMAID.java | 4 ++-- src/main/java/org/catmaid/Tiler.java | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index c5fa25d..71ca81a 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -156,7 +156,7 @@ static protected class Param public int sourceTileHeight; public double sourceResXY; public double sourceResZ; - + /* export */ /* source interval (crop area) in isotropic pixel coordinates */ public Interval sourceInterval; @@ -252,8 +252,8 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) Long.toString( ( long )Math.ceil( ( double )orientedSourceInterval.dimension( 0 ) / ( double )p.tileWidth ) - 1 ) ) ); p.exportPath = System.getProperty( "exportBasePath", "" ); - p.tilePattern = System.getProperty( "tilePattern", "%5$d/%8$d_%9$d_%1$d" ); // default is z/row_col_scale p.format = System.getProperty( "format", "jpg" ); + p.tilePattern = System.getProperty( "tilePattern", "%5$d/%8$d_%9$d_%1$d" + "." + p.format); // default is z/row_col_scale.jpg p.quality = Float.parseFloat( System.getProperty( "quality", "0.85" ) ); final String type = System.getProperty( "type", "rgb" ); if ( type.equalsIgnoreCase( "gray" ) || type.equalsIgnoreCase( "grey" ) ) diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java index 9f1d225..b06ae50 100644 --- a/src/main/java/org/catmaid/Tiler.java +++ b/src/main/java/org/catmaid/Tiler.java @@ -215,8 +215,6 @@ public void tile( new StringBuffer(exportPath) .append( "/" ) .append(String.format(tilePattern, 0, 1.0, min[0], min[1], z, tileWidth, tileHeight, r, c)) - .append( "." ) - .append( format ) .toString(); Util.writeTile( imgCopy, tilePath, format, quality ); From 7a7a073a9119d003017fdf2751a9789a49d49dc9 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Thu, 8 Oct 2015 10:39:25 -0400 Subject: [PATCH 06/35] removed print statements --- src/main/java/org/catmaid/ScaleCATMAID.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/catmaid/ScaleCATMAID.java b/src/main/java/org/catmaid/ScaleCATMAID.java index 97cfe59..b5a6bab 100644 --- a/src/main/java/org/catmaid/ScaleCATMAID.java +++ b/src/main/java/org/catmaid/ScaleCATMAID.java @@ -132,11 +132,9 @@ final static protected BufferedImage open( final BufferedImage alternative, final int type ) { - System.out.println("Read " + path); final File file = new File( path ); if ( file.exists() ) { - System.out.println("Found " + path); try { return ImageIO.read( new File( path ) ); From 4d563400464159f57c9d4ee8864c17fa2ec5a260 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Wed, 28 Oct 2015 14:25:25 -0400 Subject: [PATCH 07/35] prevent crating an absolute path when no output path is provided --- src/main/java/org/catmaid/Tiler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java index b06ae50..849e42a 100644 --- a/src/main/java/org/catmaid/Tiler.java +++ b/src/main/java/org/catmaid/Tiler.java @@ -212,8 +212,8 @@ public void tile( img.getRaster().setDataElements( 0, 0, tileWidth, tileHeight, tilePixels ); final BufferedImage imgCopy = Util.draw( img, type ); final String tilePath = - new StringBuffer(exportPath) - .append( "/" ) + new StringBuffer(exportPath != null && exportPath.trim().length() > 0 ? exportPath : "") + .append(exportPath != null && exportPath.trim().length() > 0 ? "/" : "") .append(String.format(tilePattern, 0, 1.0, min[0], min[1], z, tileWidth, tileHeight, r, c)) .toString(); From 96d8fd6088b58789964c71ad1da5825977609ad3 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Wed, 28 Oct 2015 15:14:42 -0400 Subject: [PATCH 08/35] remove commented code --- src/main/java/org/catmaid/Tiler.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java index 849e42a..029d696 100644 --- a/src/main/java/org/catmaid/Tiler.java +++ b/src/main/java/org/catmaid/Tiler.java @@ -179,11 +179,7 @@ public void tile( view = source; viewInterval = sourceInterval; } - -// final long maxC = -// final long maxR = ( long ) Math.ceil( ( double ) viewInterval.dimension( 1 ) / ( double ) tileHeight ) - 1; -// final long maxZ = viewInterval.dimension( 2 ) - 1; -// + final long[] min = new long[ 3 ]; final long[] size = new long[ 3 ]; size[ 2 ] = 1; From c770c821319c4ee30614ea66a97cbbdec9407c80 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Wed, 28 Oct 2015 15:17:04 -0400 Subject: [PATCH 09/35] debug message to show successful loading of a tile --- src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index 6801dc2..ffc441a 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -671,6 +671,7 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) { final URL url = new URL( urlString ); final BufferedImage jpg = ImageIO.read( url ); + System.out.println( "successfully loaded r=" + r + " c=" + c + " url(" + urlString + ")" ); /* This gymnastic is necessary to get reproducible gray * values, just opening a JPG or PNG, even when saved by @@ -683,8 +684,6 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) pg.grabPixels(); cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) ); -// System.out.println( "success loading r=" + r + " c=" + c + " url(" + urlString + ")" ); - } catch (final IOException e) { From 3bd2736350b37ce91e90e0828106d0d8b737e728 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Wed, 28 Oct 2015 15:20:11 -0400 Subject: [PATCH 10/35] commented debug message --- src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index ffc441a..f021a48 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -671,7 +671,6 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) { final URL url = new URL( urlString ); final BufferedImage jpg = ImageIO.read( url ); - System.out.println( "successfully loaded r=" + r + " c=" + c + " url(" + urlString + ")" ); /* This gymnastic is necessary to get reproducible gray * values, just opening a JPG or PNG, even when saved by @@ -684,6 +683,7 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) pg.grabPixels(); cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) ); +// System.out.println( "successfully loaded r=" + r + " c=" + c + " url(" + urlString + ")" ); } catch (final IOException e) { From 4ecc8263c854c6f35aa65a5ef03df5cc25d3053e Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Tue, 3 Nov 2015 13:33:57 -0500 Subject: [PATCH 11/35] changed the tiler to ignore empty tiles as well --- .gitignore | 2 + src/main/java/org/catmaid/TileCATMAID.java | 14 ++--- src/main/java/org/catmaid/Tiler.java | 68 +++++++++++++--------- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/.gitignore b/.gitignore index b1fad23..aae6782 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ target .classpath .project .settings +*.iml +.idea \ No newline at end of file diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index 71ca81a..ae63e7a 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -174,6 +174,7 @@ static protected class Param public String format; public float quality; public int type; + public boolean ignoreEmptyTiles; public TileCATMAID.Interpolation interpolation; } @@ -260,7 +261,8 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) p.type = BufferedImage.TYPE_BYTE_GRAY; else p.type = BufferedImage.TYPE_INT_RGB; - + p.ignoreEmptyTiles = Boolean.valueOf(System.getProperty( "ignoreEmptyTiles")); + final String interpolation = System.getProperty( "interpolation", "NN" ); if ( interpolation.equalsIgnoreCase( "nl" ) || interpolation.equalsIgnoreCase( "NL" ) ) p.interpolation = Interpolation.NL; @@ -278,7 +280,7 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) * @param height of scale level 0 in pixels * @param depth of scale level 0 in pixels * @param s scale level to be used, using anything >0 will create an - * accordingly scaled source stack + * accordingly scaled source stack * @param tileWidth * @param tileHeight * @param resXY x,y-resolution @@ -288,7 +290,7 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) * to isotropic resolution (if that is desired, you will want to do * it when exporting re-sliced stacks, not when extracting at the * original orientation). - * + * * @return */ static public Tiler fromCATMAID( @@ -348,9 +350,6 @@ static public Tiler fromCATMAID( return new Tiler( scaled ); } - - - final static public void main( final String[] args ) throws Exception { final Param p = parseParameters(); @@ -394,6 +393,7 @@ final static public void main( final String[] args ) throws Exception p.tilePattern, p.format, p.quality, - p.type ); + p.type, + p.ignoreEmptyTiles ); } } diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java index 029d696..f9dca2c 100644 --- a/src/main/java/org/catmaid/Tiler.java +++ b/src/main/java/org/catmaid/Tiler.java @@ -61,15 +61,20 @@ static public enum Orientation * @param sourceTile * @param targetTile */ - final static protected < T extends Type< T > > void copyTile( - final RandomAccessibleInterval< T > sourceTile, - final RandomAccessibleInterval< T > targetTile ) + final static private boolean copyTile( + final RandomAccessibleInterval< ARGBType > sourceTile, + final RandomAccessibleInterval< ARGBType > targetTile ) { - final Cursor< T > src = Views.flatIterable( sourceTile ).cursor(); - final Cursor< T > dst = Views.flatIterable( targetTile ).cursor(); + final Cursor< ARGBType > src = Views.flatIterable( sourceTile ).cursor(); + final Cursor< ARGBType > dst = Views.flatIterable( targetTile ).cursor(); - while ( src.hasNext() ) - dst.next().set( src.next() ); + boolean hasInfo = false; + while ( src.hasNext() ) { + ARGBType spixel = src.next(); + if ((spixel.get() & 0xFFFFFF) != 0) hasInfo = true; + dst.next().set(spixel); + } + return hasInfo; } @@ -85,7 +90,7 @@ final static protected < T extends Type< T > > void copyTile( * @param yx * @param bg background value */ - final static protected void copyTile( + final static protected boolean copyTile( final RandomAccessibleInterval< ARGBType > sourceTile, final RandomAccessibleInterval< ARGBType > targetTile, final boolean yx, @@ -102,7 +107,7 @@ final static protected void copyTile( for ( final ARGBType p : Views.iterable( targetTile ) ) p.set( bg ); - raiTarget = Views.interval( targetTile, sourceTile ); + raiTarget = Views.interval( targetTile, sourceTile ); } final RandomAccessibleInterval< ARGBType > raiSource; @@ -114,7 +119,7 @@ final static protected void copyTile( else raiSource = sourceTile; - copyTile( raiSource, raiTarget ); + return copyTile( raiSource, raiTarget ); } /** @@ -156,7 +161,8 @@ public void tile( final String tilePattern, final String format, final float quality, - final int type ) throws IOException + final int type, + final boolean ignoreEmptyTiles ) throws IOException { /* orientation */ final RandomAccessibleInterval< ARGBType > view; @@ -204,16 +210,18 @@ public void tile( final RandomAccessibleInterval< ARGBType > sourceTile = Views.hyperSlice( Views.offsetInterval( view, min, size ), 2, 0 ); - copyTile( sourceTile, tile, orientation == Orientation.ZY, new ARGBType( 0 ) ); - img.getRaster().setDataElements( 0, 0, tileWidth, tileHeight, tilePixels ); - final BufferedImage imgCopy = Util.draw( img, type ); - final String tilePath = - new StringBuffer(exportPath != null && exportPath.trim().length() > 0 ? exportPath : "") - .append(exportPath != null && exportPath.trim().length() > 0 ? "/" : "") - .append(String.format(tilePattern, 0, 1.0, min[0], min[1], z, tileWidth, tileHeight, r, c)) - .toString(); - - Util.writeTile( imgCopy, tilePath, format, quality ); + boolean tileIsNotEmpty = copyTile( sourceTile, tile, orientation == Orientation.ZY, new ARGBType( 0 ) ); + if (tileIsNotEmpty || !ignoreEmptyTiles) { + img.getRaster().setDataElements(0, 0, tileWidth, tileHeight, tilePixels); + final BufferedImage imgCopy = Util.draw(img, type); + final String tilePath = + new StringBuffer(exportPath != null && exportPath.trim().length() > 0 ? exportPath : "") + .append(exportPath != null && exportPath.trim().length() > 0 ? "/" : "") + .append(String.format(tilePattern, 0, 1.0, min[0], min[1], z, tileWidth, tileHeight, r, c)) + .toString(); + + Util.writeTile(imgCopy, tilePath, format, quality); + } } } } @@ -247,7 +255,8 @@ public void tile( final String tilePattern, final String format, final float quality, - final int type ) throws IOException + final int type, + final boolean ignoreEmptyTiles ) throws IOException { final long maxC; final long maxR; @@ -286,7 +295,8 @@ public void tile( tilePattern, format, quality, - type ); + type, + ignoreEmptyTiles ); } @@ -314,7 +324,8 @@ public void tile( final String tilePattern, final String format, final float quality, - final int type ) throws IOException + final int type, + final boolean ignoreEmptyTiles ) throws IOException { tile( source, @@ -325,7 +336,8 @@ public void tile( tilePattern, format, quality, - type ); + type, + ignoreEmptyTiles ); } @@ -366,7 +378,8 @@ public void tile( final String tilePattern, final String format, final float quality, - final int type ) throws IOException + final int type, + final boolean ignoreEmptyTiles ) throws IOException { tile( source, @@ -383,6 +396,7 @@ public void tile( tilePattern, format, quality, - type ); + type, + ignoreEmptyTiles ); } } From e4730d130931b62ac12270e50cb606122dcb1b7b Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Fri, 13 Nov 2015 11:45:53 -0500 Subject: [PATCH 12/35] limited the cache size to prevent OOM errors --- .../CATMAIDRandomAccessibleInterval.java | 28 +++++++++++++------ src/main/java/org/catmaid/TileCATMAID.java | 2 +- src/main/java/org/catmaid/Tiler.java | 4 +-- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index f021a48..ebda75a 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -42,7 +42,8 @@ import java.io.IOException; import java.lang.ref.SoftReference; import java.net.URL; -import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; import javax.imageio.ImageIO; @@ -590,14 +591,15 @@ public CATMAIDRandomAccess copyRandomAccess() return copy(); } } - - final protected HashMap< Key, SoftReference< Entry > > cache = new HashMap< CATMAIDRandomAccessibleInterval.Key, SoftReference< Entry > >(); - final protected String urlFormat; - final protected long rows, cols, s; - final protected int tileWidth, tileHeight; - final protected double scale; - - + + private static final int MAX_CACHE_SIZE = 25; + + final private Map< Key, SoftReference< Entry > > cache; + final private String urlFormat; + final private long rows, cols, s; + final private int tileWidth, tileHeight; + final private double scale; + public CATMAIDRandomAccessibleInterval( final String urlFormat, final long width, @@ -618,6 +620,13 @@ public CATMAIDRandomAccessibleInterval( max[ 0 ] = ( long )( width * scale ) - 1; max[ 1 ] = ( long )( height * scale ) - 1; max[ 2 ] = depth - 1; + cache = + new LinkedHashMap> (MAX_CACHE_SIZE * 10/7, 0.7f, true) { + @Override + protected boolean removeEldestEntry(Map.Entry> eldest) { + return size() > MAX_CACHE_SIZE; + } + }; } @Override @@ -669,6 +678,7 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) final int[] pixels = new int[ tileWidth * tileHeight ]; try { +// System.out.println( "Load r=" + r + " c=" + c + " url(" + urlString + ")" ); final URL url = new URL( urlString ); final BufferedImage jpg = ImageIO.read( url ); diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index ae63e7a..e370f3f 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -264,7 +264,7 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) p.ignoreEmptyTiles = Boolean.valueOf(System.getProperty( "ignoreEmptyTiles")); final String interpolation = System.getProperty( "interpolation", "NN" ); - if ( interpolation.equalsIgnoreCase( "nl" ) || interpolation.equalsIgnoreCase( "NL" ) ) + if ( interpolation.equalsIgnoreCase( "NL" ) ) p.interpolation = Interpolation.NL; else p.interpolation = Interpolation.NN; diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java index f9dca2c..3aa42f9 100644 --- a/src/main/java/org/catmaid/Tiler.java +++ b/src/main/java/org/catmaid/Tiler.java @@ -189,11 +189,11 @@ public void tile( final long[] min = new long[ 3 ]; final long[] size = new long[ 3 ]; size[ 2 ] = 1; - + final int[] tilePixels = new int[ tileWidth * tileHeight ]; final ArrayImg< ARGBType, IntArray > tile = ArrayImgs.argbs( tilePixels, tileWidth, tileHeight ); final BufferedImage img = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); - + for ( long z = minZ; z <= maxZ; ++z ) { min[ 2 ] = z + viewInterval.min( 2 ); From 13a3a1a18287b3b1a45eb91881a0f5da194bbe7e Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Wed, 18 Nov 2015 10:55:53 -0500 Subject: [PATCH 13/35] configurable bg value --- src/main/java/org/catmaid/TileCATMAID.java | 5 ++- src/main/java/org/catmaid/Tiler.java | 36 ++++++++++++++-------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index e370f3f..32ce2d6 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -175,6 +175,7 @@ static protected class Param public float quality; public int type; public boolean ignoreEmptyTiles; + public int bgValue; public TileCATMAID.Interpolation interpolation; } @@ -262,6 +263,7 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) else p.type = BufferedImage.TYPE_INT_RGB; p.ignoreEmptyTiles = Boolean.valueOf(System.getProperty( "ignoreEmptyTiles")); + p.bgValue = Integer.valueOf(System.getProperty( "bgValue", "0")); final String interpolation = System.getProperty( "interpolation", "NN" ); if ( interpolation.equalsIgnoreCase( "NL" ) ) @@ -394,6 +396,7 @@ final static public void main( final String[] args ) throws Exception p.format, p.quality, p.type, - p.ignoreEmptyTiles ); + p.ignoreEmptyTiles, + p.bgValue ); } } diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java index 3aa42f9..78eb83e 100644 --- a/src/main/java/org/catmaid/Tiler.java +++ b/src/main/java/org/catmaid/Tiler.java @@ -26,7 +26,6 @@ import net.imglib2.img.array.ArrayImg; import net.imglib2.img.array.ArrayImgs; import net.imglib2.img.basictypeaccess.array.IntArray; -import net.imglib2.type.Type; import net.imglib2.type.numeric.ARGBType; import net.imglib2.util.Intervals; import net.imglib2.view.Views; @@ -63,7 +62,8 @@ static public enum Orientation */ final static private boolean copyTile( final RandomAccessibleInterval< ARGBType > sourceTile, - final RandomAccessibleInterval< ARGBType > targetTile ) + final RandomAccessibleInterval< ARGBType > targetTile, + final ARGBType bg ) { final Cursor< ARGBType > src = Views.flatIterable( sourceTile ).cursor(); final Cursor< ARGBType > dst = Views.flatIterable( targetTile ).cursor(); @@ -71,7 +71,9 @@ final static private boolean copyTile( boolean hasInfo = false; while ( src.hasNext() ) { ARGBType spixel = src.next(); - if ((spixel.get() & 0xFFFFFF) != 0) hasInfo = true; + if ((spixel.get() & 0xFFFFFF) != bg.get()) { + hasInfo = true; + } dst.next().set(spixel); } return hasInfo; @@ -90,7 +92,7 @@ final static private boolean copyTile( * @param yx * @param bg background value */ - final static protected boolean copyTile( + final static private boolean copyTile( final RandomAccessibleInterval< ARGBType > sourceTile, final RandomAccessibleInterval< ARGBType > targetTile, final boolean yx, @@ -119,7 +121,7 @@ final static protected boolean copyTile( else raiSource = sourceTile; - return copyTile( raiSource, raiTarget ); + return copyTile( raiSource, raiTarget, bg ); } /** @@ -162,7 +164,8 @@ public void tile( final String format, final float quality, final int type, - final boolean ignoreEmptyTiles ) throws IOException + final boolean ignoreEmptyTiles, + final int bgValue ) throws IOException { /* orientation */ final RandomAccessibleInterval< ARGBType > view; @@ -193,6 +196,7 @@ public void tile( final int[] tilePixels = new int[ tileWidth * tileHeight ]; final ArrayImg< ARGBType, IntArray > tile = ArrayImgs.argbs( tilePixels, tileWidth, tileHeight ); final BufferedImage img = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); + final ARGBType bg = new ARGBType( ARGBType.rgba(bgValue, bgValue, bgValue, 0) ); for ( long z = minZ; z <= maxZ; ++z ) { @@ -210,7 +214,7 @@ public void tile( final RandomAccessibleInterval< ARGBType > sourceTile = Views.hyperSlice( Views.offsetInterval( view, min, size ), 2, 0 ); - boolean tileIsNotEmpty = copyTile( sourceTile, tile, orientation == Orientation.ZY, new ARGBType( 0 ) ); + boolean tileIsNotEmpty = copyTile( sourceTile, tile, orientation == Orientation.ZY, bg ); if (tileIsNotEmpty || !ignoreEmptyTiles) { img.getRaster().setDataElements(0, 0, tileWidth, tileHeight, tilePixels); final BufferedImage imgCopy = Util.draw(img, type); @@ -256,7 +260,8 @@ public void tile( final String format, final float quality, final int type, - final boolean ignoreEmptyTiles ) throws IOException + final boolean ignoreEmptyTiles, + final int bgValue) throws IOException { final long maxC; final long maxR; @@ -296,7 +301,8 @@ public void tile( format, quality, type, - ignoreEmptyTiles ); + ignoreEmptyTiles, + bgValue ); } @@ -325,7 +331,8 @@ public void tile( final String format, final float quality, final int type, - final boolean ignoreEmptyTiles ) throws IOException + final boolean ignoreEmptyTiles, + final int bgValue ) throws IOException { tile( source, @@ -337,7 +344,8 @@ public void tile( format, quality, type, - ignoreEmptyTiles ); + ignoreEmptyTiles, + bgValue ); } @@ -379,7 +387,8 @@ public void tile( final String format, final float quality, final int type, - final boolean ignoreEmptyTiles ) throws IOException + final boolean ignoreEmptyTiles, + final int bgValue ) throws IOException { tile( source, @@ -397,6 +406,7 @@ public void tile( format, quality, type, - ignoreEmptyTiles ); + ignoreEmptyTiles, + bgValue ); } } From 62566b20f463d835eddb2d86d23a118bb469d61c Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Tue, 8 Dec 2015 12:35:50 -0500 Subject: [PATCH 14/35] changes to allow me to save an orthoview at the proper offset --- src/main/java/org/catmaid/TileCATMAID.java | 167 +++++++++++++-------- src/main/java/org/catmaid/Tiler.java | 42 ++++-- 2 files changed, 130 insertions(+), 79 deletions(-) diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index 32ce2d6..9e505e6 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -160,6 +160,7 @@ static protected class Param /* export */ /* source interval (crop area) in isotropic pixel coordinates */ public Interval sourceInterval; + public Interval realWorldOrientedCroppedInterval; public Tiler.Orientation orientation; public int tileWidth; public int tileHeight; @@ -192,15 +193,11 @@ static protected Param parseParameters() p.sourceDepth = Long.parseLong( System.getProperty( "sourceDepth", "0" ) ); p.sourceScaleLevel = Long.parseLong( System.getProperty( "sourceScaleLevel", "0" ) ); - final int scaleXYDiv = 1 << p.sourceScaleLevel; - p.sourceTileWidth = Integer.parseInt( System.getProperty( "sourceTileWidth", "256" ) ); p.sourceTileHeight = Integer.parseInt( System.getProperty( "sourceTileHeight", "256" ) ); p.sourceResXY = Double.parseDouble( System.getProperty( "sourceResXY", "1.0" ) ); p.sourceResZ = Double.parseDouble( System.getProperty( "sourceResZ", "1.0" ) ); - final double scaleZDiv = scaleXYDiv * p.sourceResXY / p.sourceResZ; - /* export */ final long minX = Long.parseLong( System.getProperty( "minX", "0" ) ); final long minY = Long.parseLong( System.getProperty( "minY", "0" ) ); @@ -208,50 +205,89 @@ static protected Param parseParameters() final long width = Long.parseLong( System.getProperty( "width", "0" ) ); final long height = Long.parseLong( System.getProperty( "height", "0" ) ); final long depth = Long.parseLong( System.getProperty( "depth", "0" ) ); + p.tileWidth = Integer.parseInt( System.getProperty( "tileWidth", "256" ) ); + p.tileHeight = Integer.parseInt( System.getProperty( "tileHeight", "256" ) ); + // sourceInterval is the interval in pixel coordinates at the sourceScaleLevel p.sourceInterval = new FinalInterval( new long[]{ minX, minY, minZ }, new long[]{ minX + width - 1, minY + height - 1, minZ + depth - 1 } ); - final FinalDimensions orientedSourceInterval; final String orientation = System.getProperty( "orientation", "xy" ); + final double tileWidth; + final double tileHeight; + final double zFactor; if ( orientation.equalsIgnoreCase( "xz" ) ) { p.orientation = Orientation.XZ; - orientedSourceInterval = new FinalDimensions( - p.sourceInterval.dimension( 0 ) / scaleXYDiv, - ( long )( p.sourceInterval.dimension( 2 ) / scaleZDiv ), - p.sourceInterval.dimension( 1 ) / scaleXYDiv ); + p.realWorldOrientedCroppedInterval = new FinalInterval( + new long[] { + (long) (p.sourceInterval.min(0) * p.sourceResXY), + (long) (p.sourceInterval.min(2) * p.sourceResZ), + (long) (p.sourceInterval.min(1) * p.sourceResXY) + }, + new long[]{ + (long) (p.sourceInterval.max(0) * p.sourceResXY), + (long) (p.sourceInterval.max(2) * p.sourceResZ), + (long) (p.sourceInterval.max(1) * p.sourceResXY) + } + ); + tileWidth = p.tileWidth * p.sourceResXY; + tileHeight = p.tileHeight * p.sourceResZ; + zFactor = p.sourceResXY; } else if ( orientation.equalsIgnoreCase( "zy" ) ) { p.orientation = Orientation.ZY; - orientedSourceInterval = new FinalDimensions( - ( long )( p.sourceInterval.dimension( 2 ) / scaleZDiv ), - p.sourceInterval.dimension( 1 ) / scaleXYDiv, - p.sourceInterval.dimension( 0 ) / scaleXYDiv ); + p.realWorldOrientedCroppedInterval = new FinalInterval( + new long[] { + (long) (p.sourceInterval.min(2) * p.sourceResZ), + (long) (p.sourceInterval.min(1) * p.sourceResXY), + (long) (p.sourceInterval.min(0) * p.sourceResXY) + }, + new long[] { + (long) (p.sourceInterval.max(2) * p.sourceResZ), + (long) (p.sourceInterval.max(1) * p.sourceResXY), + (long) (p.sourceInterval.max(0) * p.sourceResXY) + } + ); + tileWidth = p.tileWidth * p.sourceResZ; + tileHeight = p.tileHeight * p.sourceResXY; + zFactor = p.sourceResXY; } else { p.orientation = Orientation.XY; - orientedSourceInterval = new FinalDimensions( - p.sourceInterval.dimension( 0 ) / scaleXYDiv, - p.sourceInterval.dimension( 1 ) / scaleXYDiv, - ( long )( p.sourceInterval.dimension( 2 ) / scaleZDiv ) ); + p.realWorldOrientedCroppedInterval = new FinalInterval( + new long[] { + (long) (p.sourceInterval.min(0) * p.sourceResXY), + (long) (p.sourceInterval.min(1) * p.sourceResXY), + (long) (p.sourceInterval.min(2) * p.sourceResZ) + }, + new long[] { + (long) (p.sourceInterval.max(0) * p.sourceResXY), + (long) (p.sourceInterval.max(1) * p.sourceResXY), + (long) (p.sourceInterval.max(2) * p.sourceResZ) + } + ); + tileWidth = p.tileWidth * p.sourceResXY; + tileHeight = p.tileHeight * p.sourceResXY; + zFactor = p.sourceResZ; } - p.tileWidth = Integer.parseInt( System.getProperty( "tileWidth", "256" ) ); - p.tileHeight = Integer.parseInt( System.getProperty( "tileHeight", "256" ) ); - p.minZ = Long.parseLong( System.getProperty( "exportMinZ", "0" ) ); + p.minZ = Long.parseLong( System.getProperty( "exportMinZ", + Long.toString( ( long )(p.realWorldOrientedCroppedInterval.min( 2 ) / zFactor ) ) ) ); p.maxZ = Long.parseLong( System.getProperty( "exportMaxZ", - Long.toString( orientedSourceInterval.dimension( 2 ) - 1 ) ) ); - p.minR = Long.parseLong( System.getProperty( "exportMinR", "0" ) ); + Long.toString( ( long )Math.ceil( ( double )p.realWorldOrientedCroppedInterval.max( 2 ) / zFactor ) - 1 ) ) ); + p.minR = Long.parseLong( System.getProperty( "exportMinR", + Long.toString( ( long )(p.realWorldOrientedCroppedInterval.min( 1 ) / tileHeight ) ) ) ); p.maxR = Long.parseLong( System.getProperty( "exportMaxR", - Long.toString( ( long )Math.ceil( ( double )orientedSourceInterval.dimension( 1 ) / ( double )p.tileHeight ) - 1 ) ) ); - p.minC = Long.parseLong( System.getProperty( "exportMinC", "0" ) ); + Long.toString( ( long )Math.ceil( ( double )p.realWorldOrientedCroppedInterval.max( 1 ) / tileHeight ) - 1 ) ) ); + p.minC = Long.parseLong( System.getProperty( "exportMinC" , + Long.toString( ( long )( p.realWorldOrientedCroppedInterval.min( 0 ) / tileWidth ) ) ) ); p.maxC = Long.parseLong( System.getProperty( "exportMaxC", - Long.toString( ( long )Math.ceil( ( double )orientedSourceInterval.dimension( 0 ) / ( double )p.tileWidth ) - 1 ) ) ); + Long.toString( ( long )Math.ceil( ( double )p.realWorldOrientedCroppedInterval.max( 0 ) / tileWidth ) - 1 ) ) ); p.exportPath = System.getProperty( "exportBasePath", "" ); p.format = System.getProperty( "format", "jpg" ); @@ -273,7 +309,7 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) return p; } - + /** * Create a {@link Tiler} from a CATMAID stack. * @@ -286,7 +322,7 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) * @param tileWidth * @param tileHeight * @param resXY x,y-resolution - * @param real valued offset in CATMAID scale level 0 pixels + * @param cropped interval in CATMAID scale level 0 pixels * @param resZ z-resolution, what matters is only the ratio * between z- and x,y-resolution to scale the source * to isotropic resolution (if that is desired, you will want to do @@ -295,7 +331,7 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) * * @return */ - static public Tiler fromCATMAID( + static private Tiler fromCATMAID( final String urlFormat, final long width, final long height, @@ -305,7 +341,7 @@ static public Tiler fromCATMAID( final int tileHeight, final double resXY, final double resZ, - final RealLocalizable offset, + final Interval croppedInterval, final Interpolation interpolation ) { final CATMAIDRandomAccessibleInterval catmaidStack = @@ -319,56 +355,54 @@ static public Tiler fromCATMAID( tileHeight ); /* scale and re-raster */ - final double scaleXY = 1.0 / ( 1 << s ); - final double scaleZ = resZ / resXY * scaleXY; - - final double offsetX = offset.getDoublePosition( 0 ) * scaleXY; - final double offsetY = offset.getDoublePosition( 1 ) * scaleXY; - final double offsetZ = offset.getDoublePosition( 2 ) * scaleZ; - + final double scaleXY = resXY * (1 << s); + final double scaleZ = resZ; + final RealPoint offset = new RealPoint( 3 ); + croppedInterval.min(offset); + + final double offsetX = offset.getDoublePosition( 0 ) * resXY; + final double offsetY = offset.getDoublePosition( 1 ) * resXY; + final double offsetZ = offset.getDoublePosition( 2 ) * resZ; + final AffineTransform3D transform = new AffineTransform3D(); transform.set( - 1, 0, 0, -offsetX, - 0, 1, 0, -offsetY, + scaleXY, 0, 0, -offsetX, + 0, scaleXY, 0, -offsetY, 0, 0, scaleZ, -offsetZ ); - final RealRandomAccessible< ARGBType > interpolant; + final RealRandomAccessible< ARGBType > interpolatedStack; switch ( interpolation ) { case NL: - interpolant = Views.interpolate( catmaidStack, new NLinearInterpolatorARGBFactory() ); + interpolatedStack = Views.interpolate( catmaidStack, new NLinearInterpolatorARGBFactory() ); break; default: - interpolant = Views.interpolate( catmaidStack, new NearestNeighborInterpolatorFactory< ARGBType >() ); + interpolatedStack = Views.interpolate( catmaidStack, new NearestNeighborInterpolatorFactory< ARGBType >() ); } - final RandomAccessible< ARGBType > scaledInterpolant = RealViews.affine( interpolant, transform ); - final RandomAccessibleInterval< ARGBType > scaled = + final RandomAccessible< ARGBType > scaledInterpolatedStack = RealViews.affine( interpolatedStack, transform ); + final RandomAccessibleInterval< ARGBType > croppedView = Views.interval( - scaledInterpolant, + scaledInterpolatedStack, new FinalInterval( - ( long )( scaleXY * width - offsetX ), - ( long )( scaleXY * height - offsetY ), - ( long )( scaleZ * depth - offsetZ ) ) ); - - return new Tiler( scaled ); + new long[] { + (long) offsetX, + (long) offsetY, + (long) offsetZ + }, + new long[] { + (long) (offsetX + resXY * croppedInterval.dimension(0)), + (long) (offsetY + resXY * croppedInterval.dimension(1)), + (long) (offsetZ + resZ * croppedInterval.dimension(2)) + } + ) ); + return new Tiler( croppedView ); } - + final static public void main( final String[] args ) throws Exception { final Param p = parseParameters(); - + System.out.println( "sourceInterval: " + Util.printInterval( p.sourceInterval ) ); - - final RealPoint min = new RealPoint( 3 ); - p.sourceInterval.min( min ); - - final int scaleXYDiv = 1 << p.sourceScaleLevel; - final double scaleZDiv = scaleXYDiv * p.sourceResXY / p.sourceResZ; - - final FinalInterval cropDimensions = new FinalInterval( - p.sourceInterval.dimension( 0 ) / scaleXYDiv, - p.sourceInterval.dimension( 1 ) / scaleXYDiv, - ( long )( p.sourceInterval.dimension( 2 ) / scaleZDiv ) ); - + fromCATMAID( p.sourceUrlFormat, p.sourceWidth, @@ -379,9 +413,9 @@ final static public void main( final String[] args ) throws Exception p.sourceTileHeight, p.sourceResXY, p.sourceResZ, - min, + p.sourceInterval, p.interpolation ).tile( - cropDimensions, + p.sourceInterval, p.orientation, p.tileWidth, p.tileHeight, @@ -397,6 +431,7 @@ final static public void main( final String[] args ) throws Exception p.quality, p.type, p.ignoreEmptyTiles, - p.bgValue ); + p.bgValue, + p.sourceResZ / p.sourceResXY ); } } diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java index 78eb83e..275d1d3 100644 --- a/src/main/java/org/catmaid/Tiler.java +++ b/src/main/java/org/catmaid/Tiler.java @@ -146,6 +146,8 @@ final static private boolean copyTile( * @param format * @param quality * @param type + * @param bgValue background pixel value + * @param zScaleFactor the step factor for z scanning * @throws IOException */ public void tile( @@ -165,7 +167,8 @@ public void tile( final float quality, final int type, final boolean ignoreEmptyTiles, - final int bgValue ) throws IOException + final int bgValue, + final double zStepFactor ) throws IOException { /* orientation */ final RandomAccessibleInterval< ARGBType > view; @@ -178,7 +181,7 @@ public void tile( new long[]{ sourceInterval.min( 0 ), sourceInterval.min( 2 ), sourceInterval.min( 1 ) }, new long[]{ sourceInterval.max( 0 ), sourceInterval.max( 2 ), sourceInterval.max( 1 ) } ); break; - case ZY: + case ZY: view = Views.permute( source, 0, 2 ); viewInterval = new FinalInterval( new long[]{ sourceInterval.min( 2 ), sourceInterval.min( 1 ), sourceInterval.min( 0 ) }, @@ -197,18 +200,19 @@ public void tile( final ArrayImg< ARGBType, IntArray > tile = ArrayImgs.argbs( tilePixels, tileWidth, tileHeight ); final BufferedImage img = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); final ARGBType bg = new ARGBType( ARGBType.rgba(bgValue, bgValue, bgValue, 0) ); + final long zStep = (long) Math.max(zStepFactor, 1); - for ( long z = minZ; z <= maxZ; ++z ) + for ( long z = minZ; z <= maxZ; z += zStep ) { - min[ 2 ] = z + viewInterval.min( 2 ); + min[ 2 ] = z; for ( long r = minR; r <= maxR; ++r ) { - min[ 1 ] = r * tileHeight + viewInterval.min( 1 ); + min[ 1 ] = r * tileHeight; final long max1 = Math.min( viewInterval.max( 1 ), min[ 1 ] + tileHeight - 1 ); size[ 1 ] = max1 - min[ 1 ] + 1; for ( long c = minC; c <= maxC; ++c ) { - min[ 0 ] = c * tileWidth + viewInterval.min( 0 ); + min[ 0 ] = c * tileWidth; final long max0 = Math.min( viewInterval.max( 0 ), min[ 0 ] + tileWidth - 1 ); size[ 0 ] = max0 - min[ 0 ] + 1; @@ -237,7 +241,7 @@ public void tile( * {@link RandomAccessibleInterval}. That is you can choose the * window to be exported. * - * @param sourceInterval the interval of the source to be exported + * @param sourceInterval the interval of the source to be exported * @param orientation the export orientation * @param tileWidth * @param tileHeight @@ -248,6 +252,8 @@ public void tile( * @param format * @param quality * @param type + * @param bgValue background pixel value + * @param zStepFactor the step factor for z scanning * @throws IOException */ public void tile( @@ -261,7 +267,8 @@ public void tile( final float quality, final int type, final boolean ignoreEmptyTiles, - final int bgValue) throws IOException + final int bgValue, + final double zStepFactor ) throws IOException { final long maxC; final long maxR; @@ -302,7 +309,8 @@ public void tile( quality, type, ignoreEmptyTiles, - bgValue ); + bgValue, + zStepFactor ); } @@ -320,6 +328,8 @@ public void tile( * @param format * @param quality * @param type + * @param bgValue background pixel value + * @param zStepFactor the step factor for z scanning * @throws IOException */ public void tile( @@ -332,7 +342,8 @@ public void tile( final float quality, final int type, final boolean ignoreEmptyTiles, - final int bgValue ) throws IOException + final int bgValue, + final double zStepFactor ) throws IOException { tile( source, @@ -345,7 +356,8 @@ public void tile( quality, type, ignoreEmptyTiles, - bgValue ); + bgValue, + zStepFactor ); } @@ -370,6 +382,8 @@ public void tile( * @param quality quality for jpg-compression if format is "jpg" * @param type the type of export tiles, e.g. * {@link BufferedImage#TYPE_BYTE_GRAY} + * @param bgValue background pixel value + * @param zStepFactor the step factor for z scanning * @throws IOException */ public void tile( @@ -388,7 +402,8 @@ public void tile( final float quality, final int type, final boolean ignoreEmptyTiles, - final int bgValue ) throws IOException + final int bgValue, + final double zStepFactor ) throws IOException { tile( source, @@ -407,6 +422,7 @@ public void tile( quality, type, ignoreEmptyTiles, - bgValue ); + bgValue, + zStepFactor ); } } From 5518322444f4cabd5a361b1407e270e5a0ee5b7c Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Thu, 10 Dec 2015 13:29:07 -0500 Subject: [PATCH 15/35] use the scale level to determine the z step --- .../java/org/catmaid/CATMAIDRandomAccessibleInterval.java | 4 +--- src/main/java/org/catmaid/TileCATMAID.java | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index ebda75a..b001e24 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -140,9 +140,7 @@ public void finalize() { synchronized ( cache ) { -// System.out.println( "finalizing..." ); cache.remove( key ); -// System.out.println( cache.size() + " tiles chached." ); } } } @@ -687,7 +685,7 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) * ImageIO, and grabbing its pixels results in gray values * with a non-matching gamma transfer function, I cannot tell * why... */ - final BufferedImage image = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); + final BufferedImage image = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); image.createGraphics().drawImage( jpg, 0, 0, null ); final PixelGrabber pg = new PixelGrabber( image, 0, 0, tileWidth, tileHeight, pixels, 0, tileWidth ); pg.grabPixels(); diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index 9e505e6..0e221d8 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -432,6 +432,6 @@ final static public void main( final String[] args ) throws Exception p.type, p.ignoreEmptyTiles, p.bgValue, - p.sourceResZ / p.sourceResXY ); + (1 << p.sourceScaleLevel)); } } From 3bbd8c9ed512188206bab89ac6d69ca18f187821 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Thu, 10 Dec 2015 15:59:14 -0500 Subject: [PATCH 16/35] put z in the tile loading debug message --- .../java/org/catmaid/CATMAIDRandomAccessibleInterval.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index b001e24..27d77df 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -676,7 +676,7 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) final int[] pixels = new int[ tileWidth * tileHeight ]; try { -// System.out.println( "Load r=" + r + " c=" + c + " url(" + urlString + ")" ); + System.out.println( "Load r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); final URL url = new URL( urlString ); final BufferedImage jpg = ImageIO.read( url ); @@ -691,11 +691,11 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) pg.grabPixels(); cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) ); -// System.out.println( "successfully loaded r=" + r + " c=" + c + " url(" + urlString + ")" ); + System.out.println( "Successfully loaded r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); } catch (final IOException e) { - System.out.println( "failed loading r=" + r + " c=" + c + " url(" + urlString + ")" ); + System.out.println( "Failed loading r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) ); } catch (final InterruptedException e) From ea1b78fa9cceef2e52be98d3972ce999d1e2d5b0 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Fri, 11 Dec 2015 00:25:07 -0500 Subject: [PATCH 17/35] changed the export parameters to be pixel coordinates at level 0 --- .../CATMAIDRandomAccessibleInterval.java | 2 +- src/main/java/org/catmaid/TileCATMAID.java | 156 ++++++++---------- src/main/java/org/catmaid/Tiler.java | 40 ++--- 3 files changed, 88 insertions(+), 110 deletions(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index 27d77df..8200196 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -590,7 +590,7 @@ public CATMAIDRandomAccess copyRandomAccess() } } - private static final int MAX_CACHE_SIZE = 25; + private static final int MAX_CACHE_SIZE = 2048; final private Map< Key, SoftReference< Entry > > cache; final private String urlFormat; diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index 0e221d8..2cca484 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -160,7 +160,8 @@ static protected class Param /* export */ /* source interval (crop area) in isotropic pixel coordinates */ public Interval sourceInterval; - public Interval realWorldOrientedCroppedInterval; + public Interval scaledInterval; + public Interval orientedScaledInterval; public Tiler.Orientation orientation; public int tileWidth; public int tileHeight; @@ -212,82 +213,67 @@ static protected Param parseParameters() new long[]{ minX, minY, minZ }, new long[]{ minX + width - 1, minY + height - 1, minZ + depth - 1 } ); final String orientation = System.getProperty( "orientation", "xy" ); - final double tileWidth; - final double tileHeight; - final double zFactor; + final double scaleXY = (1 << p.sourceScaleLevel); + final double scaleZ = scaleXY * p.sourceResXY / p.sourceResZ; + final long exportedMinX = scale(Long.parseLong( System.getProperty( "exportedMinX", "0" ) ), scaleXY); + final long exportedMinY = scale(Long.parseLong( System.getProperty( "exportedMinY", "0" ) ), scaleXY); + final long exportedMinZ = scale(Long.parseLong( System.getProperty( "exportedMinZ", "0" ) ), scaleZ); + final long exportedWidth = scale(Long.parseLong( System.getProperty( "exportedWidth", + Long.toString(p.sourceInterval.dimension(0)) ) ), scaleXY); + final long exportedHeight = scale(Long.parseLong( System.getProperty( "exportedHeight", + Long.toString(p.sourceInterval.dimension(1)) ) ), scaleXY); + final long exportedDepth = scale(Long.parseLong( System.getProperty( "exportedDepth", + Long.toString(p.sourceInterval.dimension(2)) ) ), scaleZ); + + p.scaledInterval = new FinalInterval( + new long[] { exportedMinX, exportedMinY, exportedMinZ }, + new long[] { exportedMinX + exportedWidth, exportedMinY + exportedHeight, exportedMinZ + exportedDepth} + ); + if ( orientation.equalsIgnoreCase( "xz" ) ) { p.orientation = Orientation.XZ; - p.realWorldOrientedCroppedInterval = new FinalInterval( + p.orientedScaledInterval = new FinalInterval( new long[] { - (long) (p.sourceInterval.min(0) * p.sourceResXY), - (long) (p.sourceInterval.min(2) * p.sourceResZ), - (long) (p.sourceInterval.min(1) * p.sourceResXY) + p.scaledInterval.min(0), + p.scaledInterval.min(2), + p.scaledInterval.min(1) }, new long[]{ - (long) (p.sourceInterval.max(0) * p.sourceResXY), - (long) (p.sourceInterval.max(2) * p.sourceResZ), - (long) (p.sourceInterval.max(1) * p.sourceResXY) + p.scaledInterval.max(0), + p.scaledInterval.max(2), + p.scaledInterval.max(1) } ); - tileWidth = p.tileWidth * p.sourceResXY; - tileHeight = p.tileHeight * p.sourceResZ; - zFactor = p.sourceResXY; } else if ( orientation.equalsIgnoreCase( "zy" ) ) { p.orientation = Orientation.ZY; - p.realWorldOrientedCroppedInterval = new FinalInterval( + p.orientedScaledInterval = new FinalInterval( new long[] { - (long) (p.sourceInterval.min(2) * p.sourceResZ), - (long) (p.sourceInterval.min(1) * p.sourceResXY), - (long) (p.sourceInterval.min(0) * p.sourceResXY) + p.scaledInterval.min(2), + p.scaledInterval.min(1), + p.scaledInterval.min(0) }, - new long[] { - (long) (p.sourceInterval.max(2) * p.sourceResZ), - (long) (p.sourceInterval.max(1) * p.sourceResXY), - (long) (p.sourceInterval.max(0) * p.sourceResXY) + new long[]{ + p.scaledInterval.max(2), + p.scaledInterval.max(1), + p.scaledInterval.max(0) } ); - tileWidth = p.tileWidth * p.sourceResZ; - tileHeight = p.tileHeight * p.sourceResXY; - zFactor = p.sourceResXY; } else { p.orientation = Orientation.XY; - p.realWorldOrientedCroppedInterval = new FinalInterval( - new long[] { - (long) (p.sourceInterval.min(0) * p.sourceResXY), - (long) (p.sourceInterval.min(1) * p.sourceResXY), - (long) (p.sourceInterval.min(2) * p.sourceResZ) - }, - new long[] { - (long) (p.sourceInterval.max(0) * p.sourceResXY), - (long) (p.sourceInterval.max(1) * p.sourceResXY), - (long) (p.sourceInterval.max(2) * p.sourceResZ) - } - ); - tileWidth = p.tileWidth * p.sourceResXY; - tileHeight = p.tileHeight * p.sourceResXY; - zFactor = p.sourceResZ; + p.orientedScaledInterval = new FinalInterval(p.scaledInterval); } - p.minZ = Long.parseLong( System.getProperty( "exportMinZ", - Long.toString( ( long )(p.realWorldOrientedCroppedInterval.min( 2 ) / zFactor ) ) ) ); - p.maxZ = Long.parseLong( System.getProperty( - "exportMaxZ", - Long.toString( ( long )Math.ceil( ( double )p.realWorldOrientedCroppedInterval.max( 2 ) / zFactor ) - 1 ) ) ); - p.minR = Long.parseLong( System.getProperty( "exportMinR", - Long.toString( ( long )(p.realWorldOrientedCroppedInterval.min( 1 ) / tileHeight ) ) ) ); - p.maxR = Long.parseLong( System.getProperty( - "exportMaxR", - Long.toString( ( long )Math.ceil( ( double )p.realWorldOrientedCroppedInterval.max( 1 ) / tileHeight ) - 1 ) ) ); - p.minC = Long.parseLong( System.getProperty( "exportMinC" , - Long.toString( ( long )( p.realWorldOrientedCroppedInterval.min( 0 ) / tileWidth ) ) ) ); - p.maxC = Long.parseLong( System.getProperty( - "exportMaxC", - Long.toString( ( long )Math.ceil( ( double )p.realWorldOrientedCroppedInterval.max( 0 ) / tileWidth ) - 1 ) ) ); + p.minZ = p.orientedScaledInterval.min( 2 ); + p.maxZ = p.orientedScaledInterval.max( 2 ); + p.minR = ( long )(p.orientedScaledInterval.min( 1 ) / ( double )p.tileHeight ); + p.maxR = ( long )Math.ceil(p.orientedScaledInterval.max( 1 ) / ( double )p.tileHeight - 1); + p.minC = ( long )(p.orientedScaledInterval.min( 0 ) / ( double )p.tileWidth ); + p.maxC = ( long )Math.ceil(p.orientedScaledInterval.max( 0 ) / ( double )p.tileWidth - 1); p.exportPath = System.getProperty( "exportBasePath", "" ); p.format = System.getProperty( "format", "jpg" ); @@ -310,6 +296,10 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) return p; } + private static long scale(long val, double scaleFactor) { + return (long) (val / scaleFactor); + } + /** * Create a {@link Tiler} from a CATMAID stack. * @@ -322,7 +312,7 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) * @param tileWidth * @param tileHeight * @param resXY x,y-resolution - * @param cropped interval in CATMAID scale level 0 pixels + * @param offset in CATMAID scale level 0 pixels * @param resZ z-resolution, what matters is only the ratio * between z- and x,y-resolution to scale the source * to isotropic resolution (if that is desired, you will want to do @@ -341,7 +331,7 @@ static private Tiler fromCATMAID( final int tileHeight, final double resXY, final double resZ, - final Interval croppedInterval, + final RealLocalizable offset, final Interpolation interpolation ) { final CATMAIDRandomAccessibleInterval catmaidStack = @@ -355,19 +345,17 @@ static private Tiler fromCATMAID( tileHeight ); /* scale and re-raster */ - final double scaleXY = resXY * (1 << s); - final double scaleZ = resZ; - final RealPoint offset = new RealPoint( 3 ); - croppedInterval.min(offset); - - final double offsetX = offset.getDoublePosition( 0 ) * resXY; - final double offsetY = offset.getDoublePosition( 1 ) * resXY; - final double offsetZ = offset.getDoublePosition( 2 ) * resZ; + final double scaleXY = 1.0 / ( 1 << s ); + final double scaleZ = resZ / resXY * scaleXY; + + final double offsetX = offset.getDoublePosition( 0 ) * scaleXY; + final double offsetY = offset.getDoublePosition( 1 ) * scaleXY; + final double offsetZ = offset.getDoublePosition( 2 ) * scaleZ; final AffineTransform3D transform = new AffineTransform3D(); transform.set( - scaleXY, 0, 0, -offsetX, - 0, scaleXY, 0, -offsetY, + 1, 0, 0, -offsetX, + 0, 1, 0, -offsetY, 0, 0, scaleZ, -offsetZ ); final RealRandomAccessible< ARGBType > interpolatedStack; switch ( interpolation ) @@ -383,26 +371,29 @@ static private Tiler fromCATMAID( Views.interval( scaledInterpolatedStack, new FinalInterval( - new long[] { - (long) offsetX, - (long) offsetY, - (long) offsetZ - }, - new long[] { - (long) (offsetX + resXY * croppedInterval.dimension(0)), - (long) (offsetY + resXY * croppedInterval.dimension(1)), - (long) (offsetZ + resZ * croppedInterval.dimension(2)) - } - ) ); + ( long )( scaleXY * width - offsetX ), + ( long )( scaleXY * height - offsetY ), + ( long )( scaleZ * depth - offsetZ ) ) ); return new Tiler( croppedView ); } - final static public void main( final String[] args ) throws Exception + public static void main( final String[] args ) throws Exception { final Param p = parseParameters(); System.out.println( "sourceInterval: " + Util.printInterval( p.sourceInterval ) ); + final RealPoint min = new RealPoint( 3 ); + p.sourceInterval.min( min ); + + final int scaleXYDiv = 1 << p.sourceScaleLevel; + final double scaleZDiv = scaleXYDiv * p.sourceResXY / p.sourceResZ; + + final FinalInterval croppedDimensions = new FinalInterval( + p.sourceInterval.dimension( 0 ) / scaleXYDiv, + p.sourceInterval.dimension( 1 ) / scaleXYDiv, + ( long )( p.sourceInterval.dimension( 2 ) / scaleZDiv ) ); + fromCATMAID( p.sourceUrlFormat, p.sourceWidth, @@ -413,9 +404,9 @@ final static public void main( final String[] args ) throws Exception p.sourceTileHeight, p.sourceResXY, p.sourceResZ, - p.sourceInterval, + min, p.interpolation ).tile( - p.sourceInterval, + croppedDimensions, p.orientation, p.tileWidth, p.tileHeight, @@ -431,7 +422,6 @@ final static public void main( final String[] args ) throws Exception p.quality, p.type, p.ignoreEmptyTiles, - p.bgValue, - (1 << p.sourceScaleLevel)); + p.bgValue); } } diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java index 275d1d3..682e077 100644 --- a/src/main/java/org/catmaid/Tiler.java +++ b/src/main/java/org/catmaid/Tiler.java @@ -147,7 +147,6 @@ final static private boolean copyTile( * @param quality * @param type * @param bgValue background pixel value - * @param zScaleFactor the step factor for z scanning * @throws IOException */ public void tile( @@ -167,8 +166,7 @@ public void tile( final float quality, final int type, final boolean ignoreEmptyTiles, - final int bgValue, - final double zStepFactor ) throws IOException + final int bgValue ) throws IOException { /* orientation */ final RandomAccessibleInterval< ARGBType > view; @@ -181,7 +179,7 @@ public void tile( new long[]{ sourceInterval.min( 0 ), sourceInterval.min( 2 ), sourceInterval.min( 1 ) }, new long[]{ sourceInterval.max( 0 ), sourceInterval.max( 2 ), sourceInterval.max( 1 ) } ); break; - case ZY: + case ZY: view = Views.permute( source, 0, 2 ); viewInterval = new FinalInterval( new long[]{ sourceInterval.min( 2 ), sourceInterval.min( 1 ), sourceInterval.min( 0 ) }, @@ -200,20 +198,19 @@ public void tile( final ArrayImg< ARGBType, IntArray > tile = ArrayImgs.argbs( tilePixels, tileWidth, tileHeight ); final BufferedImage img = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); final ARGBType bg = new ARGBType( ARGBType.rgba(bgValue, bgValue, bgValue, 0) ); - final long zStep = (long) Math.max(zStepFactor, 1); - for ( long z = minZ; z <= maxZ; z += zStep ) + for ( long z = minZ; z <= maxZ; ++z ) { - min[ 2 ] = z; + min[ 2 ] = z + viewInterval.min( 2 ); for ( long r = minR; r <= maxR; ++r ) { - min[ 1 ] = r * tileHeight; - final long max1 = Math.min( viewInterval.max( 1 ), min[ 1 ] + tileHeight - 1 ); + min[ 1 ] = r * tileHeight + viewInterval.min( 1 ); + final long max1 = Math.min( min[ 1 ] + viewInterval.dimension( 1 ), min[ 1 ] + tileHeight - 1 ); size[ 1 ] = max1 - min[ 1 ] + 1; for ( long c = minC; c <= maxC; ++c ) { - min[ 0 ] = c * tileWidth; - final long max0 = Math.min( viewInterval.max( 0 ), min[ 0 ] + tileWidth - 1 ); + min[ 0 ] = c * tileWidth + viewInterval.min( 0 ); + final long max0 = Math.min( min[ 0 ] + viewInterval.dimension( 0 ), min[ 0 ] + tileWidth - 1 ); size[ 0 ] = max0 - min[ 0 ] + 1; final RandomAccessibleInterval< ARGBType > sourceTile = Views.hyperSlice( Views.offsetInterval( view, min, size ), 2, 0 ); @@ -253,7 +250,6 @@ public void tile( * @param quality * @param type * @param bgValue background pixel value - * @param zStepFactor the step factor for z scanning * @throws IOException */ public void tile( @@ -267,8 +263,7 @@ public void tile( final float quality, final int type, final boolean ignoreEmptyTiles, - final int bgValue, - final double zStepFactor ) throws IOException + final int bgValue ) throws IOException { final long maxC; final long maxR; @@ -309,8 +304,7 @@ public void tile( quality, type, ignoreEmptyTiles, - bgValue, - zStepFactor ); + bgValue ); } @@ -329,7 +323,6 @@ public void tile( * @param quality * @param type * @param bgValue background pixel value - * @param zStepFactor the step factor for z scanning * @throws IOException */ public void tile( @@ -342,8 +335,7 @@ public void tile( final float quality, final int type, final boolean ignoreEmptyTiles, - final int bgValue, - final double zStepFactor ) throws IOException + final int bgValue ) throws IOException { tile( source, @@ -356,8 +348,7 @@ public void tile( quality, type, ignoreEmptyTiles, - bgValue, - zStepFactor ); + bgValue ); } @@ -383,7 +374,6 @@ public void tile( * @param type the type of export tiles, e.g. * {@link BufferedImage#TYPE_BYTE_GRAY} * @param bgValue background pixel value - * @param zStepFactor the step factor for z scanning * @throws IOException */ public void tile( @@ -402,8 +392,7 @@ public void tile( final float quality, final int type, final boolean ignoreEmptyTiles, - final int bgValue, - final double zStepFactor ) throws IOException + final int bgValue ) throws IOException { tile( source, @@ -422,7 +411,6 @@ public void tile( quality, type, ignoreEmptyTiles, - bgValue, - zStepFactor ); + bgValue ); } } From 44434c9af140061b0c3f9aa3dff5d86c6fe7cf13 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Fri, 11 Dec 2015 09:26:29 -0500 Subject: [PATCH 18/35] made tile cache size a configurable parameter --- .../CATMAIDRandomAccessibleInterval.java | 10 ++- src/main/java/org/catmaid/TileCATMAID.java | 75 ++++++++++--------- 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index 8200196..56d80a3 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -605,7 +605,8 @@ public CATMAIDRandomAccessibleInterval( final long depth, final long s, final int tileWidth, - final int tileHeight ) + final int tileHeight, + final int cacheSize ) { super( 3 ); this.urlFormat = urlFormat; @@ -619,7 +620,12 @@ public CATMAIDRandomAccessibleInterval( max[ 1 ] = ( long )( height * scale ) - 1; max[ 2 ] = depth - 1; cache = - new LinkedHashMap> (MAX_CACHE_SIZE * 10/7, 0.7f, true) { + new LinkedHashMap> ( + (cacheSize > 0 ? cacheSize : MAX_CACHE_SIZE) * 10/7, + 0.7f, + true) { + private static final long serialVersionUID = 1L; + @Override protected boolean removeEldestEntry(Map.Entry> eldest) { return size() > MAX_CACHE_SIZE; diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index 2cca484..50bd344 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -18,7 +18,6 @@ import java.awt.image.BufferedImage; -import net.imglib2.FinalDimensions; import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.RandomAccessible; @@ -144,44 +143,45 @@ public class TileCATMAID { static public enum Interpolation { NN, NL }; - static protected class Param + static private class Param { /* CATMAID source stack, representing an xyz-orientation */ - public String sourceUrlFormat; - public long sourceWidth; - public long sourceHeight; - public long sourceDepth; - public long sourceScaleLevel; - public int sourceTileWidth; - public int sourceTileHeight; - public double sourceResXY; - public double sourceResZ; + String sourceUrlFormat; + long sourceWidth; + long sourceHeight; + long sourceDepth; + long sourceScaleLevel; + int sourceTileWidth; + int sourceTileHeight; + double sourceResXY; + double sourceResZ; /* export */ /* source interval (crop area) in isotropic pixel coordinates */ - public Interval sourceInterval; - public Interval scaledInterval; - public Interval orientedScaledInterval; - public Tiler.Orientation orientation; - public int tileWidth; - public int tileHeight; - public long minZ; - public long maxZ; - public long minR; - public long maxR; - public long minC; - public long maxC; - public String exportPath; - public String tilePattern; - public String format; - public float quality; - public int type; - public boolean ignoreEmptyTiles; - public int bgValue; - public TileCATMAID.Interpolation interpolation; + Interval sourceInterval; + Interval scaledInterval; + Interval orientedScaledInterval; + Tiler.Orientation orientation; + int tileWidth; + int tileHeight; + long minZ; + long maxZ; + long minR; + long maxR; + long minC; + long maxC; + String exportPath; + String tilePattern; + String format; + float quality; + int type; + boolean ignoreEmptyTiles; + int bgValue; + TileCATMAID.Interpolation interpolation; + int tileCacheSize; } - static protected Param parseParameters() + static private Param parseParameters() { final Param p = new Param(); @@ -292,7 +292,7 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) p.interpolation = Interpolation.NL; else p.interpolation = Interpolation.NN; - + p.tileCacheSize = Integer.valueOf(System.getProperty( "tileCacheSize", "1024" )); return p; } @@ -332,7 +332,8 @@ static private Tiler fromCATMAID( final double resXY, final double resZ, final RealLocalizable offset, - final Interpolation interpolation ) + final Interpolation interpolation, + final int cacheSize ) { final CATMAIDRandomAccessibleInterval catmaidStack = new CATMAIDRandomAccessibleInterval( @@ -342,7 +343,8 @@ static private Tiler fromCATMAID( depth, s, tileWidth, - tileHeight ); + tileHeight, + cacheSize ); /* scale and re-raster */ final double scaleXY = 1.0 / ( 1 << s ); @@ -405,7 +407,8 @@ public static void main( final String[] args ) throws Exception p.sourceResXY, p.sourceResZ, min, - p.interpolation ).tile( + p.interpolation, + p.tileCacheSize ).tile( croppedDimensions, p.orientation, p.tileWidth, From 93dbc4e6b90d83499f694032eaafe3ce487c819f Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Fri, 11 Dec 2015 09:56:49 -0500 Subject: [PATCH 19/35] used explicit pixel coordinates for exported max instead of the width --- README.md | 24 +++++++------- src/main/java/org/catmaid/TileCATMAID.java | 37 ++++++++++++++-------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 933885c..582c6ff 100644 --- a/README.md +++ b/README.md @@ -102,20 +102,20 @@ exported in scale level 0 pixels in xyz orientation (long, 0)
width of exported image tiles in pixels (int, 256)
tileHeight
height of exported image tiles in pixels (int, 256)
-
exportMinZ
+
exportedMinZ
first z-section index to be exported (long, 0)
-
exportMaxZ
+
exportedMaxZ
last z-section index to be exported (long, depth-1)
-
exportMinR
-
first row of tiles to be exported (long, 0)
-
exportMaxR
-
last row of tiles to be exported (long, depth-1)
-
exportMinC
-
first column of tiles to be exported (long, 0)
-
exportMaxC
-
last column of tiles to be exported (long, depth-1)
+
exportedMinX
+
first X in level 0 pixel coordinates to be exported (long, 0)
+
exportedMaxX
+
last X in level 0 pixel coordinates to be exported (long, width-1)
+
exportedMinY
+
first Y in level 0 pixel coordinates to be exported (long, 0)
+
exportedMaxY
+
last Y in level 0 pixel coordinates to be exported (long, depth-1)
exportBasePath
-
base path for the stakc to be exported (string, "")
+
base path for the stack to be exported (string, "")
tilePattern
tilePattern the file name convention for export tile coordinates without extension and base path, must contain "<s>","<z>", "<r>", @@ -155,7 +155,7 @@ contains all parameters in key=value rows (escaped according to Bash's needs). depth=100 orientation=xy exportBasePath=/var/www/catmaid/test/xy/ - tilePattern="/__" + tilePattern="%5$d/%8$d_%9$d_%1$d.jpg" format=jpg quality=0.85 type=gray diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index 50bd344..7624052 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -107,18 +107,18 @@ *
width of exported image tiles in pixels (int, 256)
*
tileHeight
*
height of exported image tiles in pixels (int, 256)
- *
exportMinZ
+ *
exportedMinZ
*
first z-section index to be exported (long, 0)
- *
exportMaxZ
+ *
exportedMaxZ
*
last z-section index to be exported (long, depth-1)
- *
exportMinR
- *
first row of tiles to be exported (long, 0)
- *
exportMaxR
- *
last row of tiles to be exported (long, depth-1)
- *
exportMinC
- *
first column of tiles to be exported (long, 0)
- *
exportMaxC
- *
last column of tiles to be exported (long, depth-1)
+ *
exportedMinX
+ *
first X in level 0 pixel coordinates to be exported (long, 0)
+ *
exportedMaxX
+ *
last X in level 0 pixel coordinates to be exported (long, width-1)
+ *
exportedMinY
+ *
first Y in level 0 pixel coordinates to be exported (long, 0)
+ *
exportedMaxY
+ *
last Y in level 0 pixel coordinates to be exported (long, height-1)
*
exportBasePath
*
base path for the stakc to be exported (string, "")
*
tilePattern
@@ -218,16 +218,25 @@ static private Param parseParameters() final long exportedMinX = scale(Long.parseLong( System.getProperty( "exportedMinX", "0" ) ), scaleXY); final long exportedMinY = scale(Long.parseLong( System.getProperty( "exportedMinY", "0" ) ), scaleXY); final long exportedMinZ = scale(Long.parseLong( System.getProperty( "exportedMinZ", "0" ) ), scaleZ); - final long exportedWidth = scale(Long.parseLong( System.getProperty( "exportedWidth", + final long exportedMaxX = scale(Long.parseLong( System.getProperty( "exportedMaxX", Long.toString(p.sourceInterval.dimension(0)) ) ), scaleXY); - final long exportedHeight = scale(Long.parseLong( System.getProperty( "exportedHeight", + if (exportedMaxX < exportedMinX) { + throw new IllegalArgumentException("The end of the X range must be greater than the beginning of the range"); + } + final long exportedMaxY = scale(Long.parseLong( System.getProperty( "exportedMaxY", Long.toString(p.sourceInterval.dimension(1)) ) ), scaleXY); - final long exportedDepth = scale(Long.parseLong( System.getProperty( "exportedDepth", + if (exportedMaxY < exportedMinY) { + throw new IllegalArgumentException("The end of the Y range must be greater than the beginning of the range"); + } + final long exportedMaxZ = scale(Long.parseLong( System.getProperty( "exportedMaxZ", Long.toString(p.sourceInterval.dimension(2)) ) ), scaleZ); + if (exportedMaxZ < exportedMinZ) { + throw new IllegalArgumentException("The end of the Z range must be greater than the beginning of the range"); + } p.scaledInterval = new FinalInterval( new long[] { exportedMinX, exportedMinY, exportedMinZ }, - new long[] { exportedMinX + exportedWidth, exportedMinY + exportedHeight, exportedMinZ + exportedDepth} + new long[] { exportedMaxX, exportedMaxY, exportedMaxZ} ); if ( orientation.equalsIgnoreCase( "xz" ) ) From 2e133d25fc0c3e622498eea9bb49ec35b9498c50 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Fri, 11 Dec 2015 10:08:37 -0500 Subject: [PATCH 20/35] don't set the tile cache size by default --- src/main/java/org/catmaid/TileCATMAID.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index 7624052..2eedbdc 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -301,7 +301,7 @@ else if ( orientation.equalsIgnoreCase( "zy" ) ) p.interpolation = Interpolation.NL; else p.interpolation = Interpolation.NN; - p.tileCacheSize = Integer.valueOf(System.getProperty( "tileCacheSize", "1024" )); + p.tileCacheSize = Integer.valueOf(System.getProperty( "tileCacheSize", "0" )); return p; } From 568c711bb41c829e2358a831ea63c6edbf6aa9b6 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Fri, 11 Dec 2015 16:12:58 -0500 Subject: [PATCH 21/35] put the previous exportMin[R,C], exportMax[R,C] parameters back such that these would take precedence if defined over the corresponding pixel coordinates, otherwise their defaults will be derived from the corresponding pixel coordinates --- src/main/java/org/catmaid/TileCATMAID.java | 106 +++++++++++++-------- src/main/java/org/catmaid/Tiler.java | 4 +- 2 files changed, 66 insertions(+), 44 deletions(-) diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index 2eedbdc..4e954e7 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -107,18 +107,36 @@ *
width of exported image tiles in pixels (int, 256)
*
tileHeight
*
height of exported image tiles in pixels (int, 256)
- *
exportedMinZ
+ *
exportMinZ
*
first z-section index to be exported (long, 0)
- *
exportedMaxZ
+ *
exportMaxZ
*
last z-section index to be exported (long, depth-1)
- *
exportedMinX
+ *
exportMinX
*
first X in level 0 pixel coordinates to be exported (long, 0)
- *
exportedMaxX
+ *
exportMaxX
*
last X in level 0 pixel coordinates to be exported (long, width-1)
- *
exportedMinY
+ *
exportMinY
*
first Y in level 0 pixel coordinates to be exported (long, 0)
- *
exportedMaxY
+ *
exportMaxY
*
last Y in level 0 pixel coordinates to be exported (long, height-1)
+ *
exportMinR
+ *
first row to be exported (long, 0). If defined it takes precedence in defining the target interval otherwise + * it is derived from exportMinY. + *
+ *
exportMaxR
+ *
last row to be exported (long, 0). If defined it takes precedence in defining the target interval otherwise + * it is derived from exportMaxY. + *
+ *
exportMinC
+ *
first column to be exported (long, 0). If defined it takes precedence in defining the target interval otherwise + * it is derived from exportMinX. + *
+ *
exportMaxC
+ *
last column to be exported (long, 0). If defined it takes precedence in defining the target interval otherwise + * it is derived from exportMaxX. + *
+ * + * *
exportBasePath
*
base path for the stakc to be exported (string, "")
*
tilePattern
@@ -159,8 +177,6 @@ static private class Param /* export */ /* source interval (crop area) in isotropic pixel coordinates */ Interval sourceInterval; - Interval scaledInterval; - Interval orientedScaledInterval; Tiler.Orientation orientation; int tileWidth; int tileHeight; @@ -215,74 +231,80 @@ static private Param parseParameters() final String orientation = System.getProperty( "orientation", "xy" ); final double scaleXY = (1 << p.sourceScaleLevel); final double scaleZ = scaleXY * p.sourceResXY / p.sourceResZ; - final long exportedMinX = scale(Long.parseLong( System.getProperty( "exportedMinX", "0" ) ), scaleXY); - final long exportedMinY = scale(Long.parseLong( System.getProperty( "exportedMinY", "0" ) ), scaleXY); - final long exportedMinZ = scale(Long.parseLong( System.getProperty( "exportedMinZ", "0" ) ), scaleZ); - final long exportedMaxX = scale(Long.parseLong( System.getProperty( "exportedMaxX", + final long exportMinX = scale(Long.parseLong( System.getProperty( "exportMinX", "0" ) ), scaleXY); + final long exportMinY = scale(Long.parseLong( System.getProperty( "exportMinY", "0" ) ), scaleXY); + final long exportMinZ = scale(Long.parseLong( System.getProperty( "exportMinZ", "0" ) ), scaleZ); + final long exportMaxX = scale(Long.parseLong( System.getProperty( "exportMaxX", Long.toString(p.sourceInterval.dimension(0)) ) ), scaleXY); - if (exportedMaxX < exportedMinX) { + + if (exportMaxX < exportMinX) { throw new IllegalArgumentException("The end of the X range must be greater than the beginning of the range"); } - final long exportedMaxY = scale(Long.parseLong( System.getProperty( "exportedMaxY", + final long exportMaxY = scale(Long.parseLong( System.getProperty( "exportMaxY", Long.toString(p.sourceInterval.dimension(1)) ) ), scaleXY); - if (exportedMaxY < exportedMinY) { + if (exportMaxY < exportMinY) { throw new IllegalArgumentException("The end of the Y range must be greater than the beginning of the range"); } - final long exportedMaxZ = scale(Long.parseLong( System.getProperty( "exportedMaxZ", + final long exportMaxZ = scale(Long.parseLong( System.getProperty( "exportMaxZ", Long.toString(p.sourceInterval.dimension(2)) ) ), scaleZ); - if (exportedMaxZ < exportedMinZ) { + if (exportMaxZ < exportMinZ) { throw new IllegalArgumentException("The end of the Z range must be greater than the beginning of the range"); } - p.scaledInterval = new FinalInterval( - new long[] { exportedMinX, exportedMinY, exportedMinZ }, - new long[] { exportedMaxX, exportedMaxY, exportedMaxZ} + final Interval scaledExportInterval = new FinalInterval( + new long[] { exportMinX, exportMinY, exportMinZ }, + new long[] { exportMaxX, exportMaxY, exportMaxZ} ); + final Interval orientedScaledInterval; if ( orientation.equalsIgnoreCase( "xz" ) ) { p.orientation = Orientation.XZ; - p.orientedScaledInterval = new FinalInterval( + orientedScaledInterval = new FinalInterval( new long[] { - p.scaledInterval.min(0), - p.scaledInterval.min(2), - p.scaledInterval.min(1) + scaledExportInterval.min(0), + scaledExportInterval.min(2), + scaledExportInterval.min(1) }, - new long[]{ - p.scaledInterval.max(0), - p.scaledInterval.max(2), - p.scaledInterval.max(1) + new long[] { + scaledExportInterval.max(0), + scaledExportInterval.max(2), + scaledExportInterval.max(1) } ); } else if ( orientation.equalsIgnoreCase( "zy" ) ) { p.orientation = Orientation.ZY; - p.orientedScaledInterval = new FinalInterval( + orientedScaledInterval = new FinalInterval( new long[] { - p.scaledInterval.min(2), - p.scaledInterval.min(1), - p.scaledInterval.min(0) + scaledExportInterval.min(2), + scaledExportInterval.min(1), + scaledExportInterval.min(0) }, new long[]{ - p.scaledInterval.max(2), - p.scaledInterval.max(1), - p.scaledInterval.max(0) + scaledExportInterval.max(2), + scaledExportInterval.max(1), + scaledExportInterval.max(0) } ); } else { p.orientation = Orientation.XY; - p.orientedScaledInterval = new FinalInterval(p.scaledInterval); + orientedScaledInterval = new FinalInterval(scaledExportInterval); } - p.minZ = p.orientedScaledInterval.min( 2 ); - p.maxZ = p.orientedScaledInterval.max( 2 ); - p.minR = ( long )(p.orientedScaledInterval.min( 1 ) / ( double )p.tileHeight ); - p.maxR = ( long )Math.ceil(p.orientedScaledInterval.max( 1 ) / ( double )p.tileHeight - 1); - p.minC = ( long )(p.orientedScaledInterval.min( 0 ) / ( double )p.tileWidth ); - p.maxC = ( long )Math.ceil(p.orientedScaledInterval.max( 0 ) / ( double )p.tileWidth - 1); + p.minZ = orientedScaledInterval.min( 2 ); + p.minR = Long.parseLong( System.getProperty( "exportMinR", + Long.toString(( long )(orientedScaledInterval.min( 1 ) / ( double )p.tileHeight )) ) ); + p.minC = Long.parseLong( System.getProperty( "exportMinC", + Long.toString(( long )(orientedScaledInterval.min( 0 ) / ( double )p.tileWidth )) ) ); + p.maxZ = orientedScaledInterval.max( 2 ); + p.maxR = Long.parseLong( System.getProperty( "exportMaxR", + Long.toString(( long )Math.ceil(orientedScaledInterval.max( 1 ) / ( double )p.tileHeight - 1) ) ) ); + p.maxC = Long.parseLong( System.getProperty( "exportMaxC", + Long.toString(( long )Math.ceil(orientedScaledInterval.max( 0 ) / ( double )p.tileWidth - 1) ) ) ); p.exportPath = System.getProperty( "exportBasePath", "" ); p.format = System.getProperty( "format", "jpg" ); diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java index 682e077..dd1b88c 100644 --- a/src/main/java/org/catmaid/Tiler.java +++ b/src/main/java/org/catmaid/Tiler.java @@ -205,12 +205,12 @@ public void tile( for ( long r = minR; r <= maxR; ++r ) { min[ 1 ] = r * tileHeight + viewInterval.min( 1 ); - final long max1 = Math.min( min[ 1 ] + viewInterval.dimension( 1 ), min[ 1 ] + tileHeight - 1 ); + final long max1 = Math.min( viewInterval.max( 1 ), min[ 1 ] + tileHeight - 1 ); size[ 1 ] = max1 - min[ 1 ] + 1; for ( long c = minC; c <= maxC; ++c ) { min[ 0 ] = c * tileWidth + viewInterval.min( 0 ); - final long max0 = Math.min( min[ 0 ] + viewInterval.dimension( 0 ), min[ 0 ] + tileWidth - 1 ); + final long max0 = Math.min( viewInterval.max( 0 ), min[ 0 ] + tileWidth - 1 ); size[ 0 ] = max0 - min[ 0 ] + 1; final RandomAccessibleInterval< ARGBType > sourceTile = Views.hyperSlice( Views.offsetInterval( view, min, size ), 2, 0 ); From c3890a984007e70cc8676068f9754ae4a0d5dae1 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Thu, 24 Dec 2015 10:04:58 -0500 Subject: [PATCH 22/35] option to set the background for the scaler as well --- src/main/java/org/catmaid/Downsampler.java | 4 +- src/main/java/org/catmaid/ScaleCATMAID.java | 44 +++++++++++++-------- src/main/java/org/catmaid/Tiler.java | 2 +- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/catmaid/Downsampler.java b/src/main/java/org/catmaid/Downsampler.java index 7b248ae..3d86360 100644 --- a/src/main/java/org/catmaid/Downsampler.java +++ b/src/main/java/org/catmaid/Downsampler.java @@ -99,7 +99,7 @@ final static public void downsampleBytes( final byte[] aPixels, final byte[] bPi } } - final static public boolean downsampleRGB( final int[] aPixels, final int[] bPixels, final int wa, final int ha ) + final static public boolean downsampleRGB( final int[] aPixels, final int[] bPixels, final int wa, final int ha, int bgValue ) { assert aPixels.length == wa * ha && bPixels.length == wa / 2 * ( ha / 2 ) : "Input dimensions do not match."; @@ -117,7 +117,7 @@ final static public boolean downsampleRGB( final int[] aPixels, final int[] bPix final int xa1 = xa + 1; int c = averageColor( ya + xa, ya + xa1, ya1 + xa, ya1 + xa1, aPixels ); bPixels[ yb + xb ] = c; - if ((c & 0xFFFFFF) != 0) { + if ((c & 0xFFFFFF) != bgValue) { bresult = true; // return true since at least one pixel is non black } } diff --git a/src/main/java/org/catmaid/ScaleCATMAID.java b/src/main/java/org/catmaid/ScaleCATMAID.java index b5a6bab..ef9f6e8 100644 --- a/src/main/java/org/catmaid/ScaleCATMAID.java +++ b/src/main/java/org/catmaid/ScaleCATMAID.java @@ -16,6 +16,7 @@ */ package org.catmaid; +import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; @@ -68,21 +69,22 @@ */ public class ScaleCATMAID { - static protected class Param + static class Param { - public int tileWidth; - public int tileHeight; - public long minX; - public long width; - public long minY; - public long height; - public long minZ; - public long maxZ; - public String tileFormat; - public String format; - public float quality; - public int type; - public boolean ignoreEmptyTiles; + int tileWidth; + int tileHeight; + long minX; + long width; + long minY; + long height; + long minZ; + long maxZ; + String tileFormat; + String format; + float quality; + int type; + boolean ignoreEmptyTiles; + int bgValue; } private ScaleCATMAID() {} @@ -123,6 +125,7 @@ static protected Param parseParameters() { throw new IllegalArgumentException("Max Y value overflow"); } } + p.bgValue = Integer.valueOf(System.getProperty( "bgValue", "0")); return p; } @@ -178,9 +181,15 @@ final public static void scale( final String format, final float quality, final int type, - final boolean ignoreEmptyTiles) throws Exception + final boolean ignoreEmptyTiles, + final int bgValue) throws Exception { final BufferedImage alternative = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); + Graphics2D alternativeG = alternative.createGraphics(); + + Color bgColor = new Color ( bgValue, bgValue, bgValue ); + alternativeG.setPaint( bgColor ); + alternativeG.fillRect ( 0, 0, alternative.getWidth(), alternative.getHeight() ); final int[] targetPixels = new int[ tileWidth * tileHeight ]; final BufferedImage target = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); @@ -272,7 +281,7 @@ final public static void scale( final PixelGrabber pg = new PixelGrabber( sourceImage, 0, 0, tileWidth * 2, tileHeight * 2, sourcePixels, 0, tileWidth * 2 ); pg.grabPixels(); - boolean notEmpty = Downsampler.downsampleRGB( sourcePixels, targetPixels, tileWidth * 2, tileHeight * 2 ); + boolean notEmpty = Downsampler.downsampleRGB( sourcePixels, targetPixels, tileWidth * 2, tileHeight * 2, bgColor.getRGB() ); if (notEmpty || !ignoreEmptyTiles) { target.getRaster().setDataElements( 0, 0, tileWidth, tileHeight, targetPixels ); @@ -308,7 +317,8 @@ final static public void scale( final Param p ) throws Exception p.format, p.quality, p.type, - p.ignoreEmptyTiles); + p.ignoreEmptyTiles, + p.bgValue); } private static final long adjustStart(long index, int tileSize) { diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java index dd1b88c..fadfac5 100644 --- a/src/main/java/org/catmaid/Tiler.java +++ b/src/main/java/org/catmaid/Tiler.java @@ -268,7 +268,7 @@ public void tile( final long maxC; final long maxR; final long maxZ; - + switch ( orientation ) { case XZ: From 058abc3cbb131c730f9d87cfc340d63ee70860b4 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Mon, 16 May 2016 20:37:12 -0400 Subject: [PATCH 23/35] http url writer --- src/main/java/org/catmaid/Util.java | 73 ++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/catmaid/Util.java b/src/main/java/org/catmaid/Util.java index d01d092..cfd1531 100644 --- a/src/main/java/org/catmaid/Util.java +++ b/src/main/java/org/catmaid/Util.java @@ -19,13 +19,18 @@ import java.awt.Image; import java.awt.image.BufferedImage; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.stream.FileImageOutputStream; +import javax.imageio.stream.ImageOutputStream; /** * @@ -57,17 +62,69 @@ final static public BufferedImage draw( imgCopy.createGraphics().drawImage( img, 0, 0, null ); return imgCopy; } - + final static public void writeTile( final BufferedImage img, - final String path, + final String url, + final String format, + final float quality ) throws IOException + { + if ( url.startsWith("file://") ) { + writeTileToFile(img, url.substring("file://".length()), format, quality); + } else if ( url.startsWith("http://") || url.startsWith("https://") ) { + writeTileToUrl(img, url, format, quality); + } else { + writeTileToFile(img, url, format, quality); + } + } + + final static private void writeTileToFile( + final BufferedImage img, + final String tileFile, + final String format, + final float quality ) throws IOException + { + new File( tileFile ).getParentFile().mkdirs(); + final FileOutputStream os = new FileOutputStream( new File( tileFile ) ); + try { + writeTile(img, os, format, quality); + } finally { + os.close(); + } + } + + final static private void writeTileToUrl( + final BufferedImage img, + final String httpUrl, + final String format, + final float quality ) throws IOException + { + URL url = new URL(httpUrl); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/octet-stream"); + OutputStream os = conn.getOutputStream(); + try { + writeTile(img, os, format, quality); + int statusCode = conn.getResponseCode(); + if (statusCode >= HttpURLConnection.HTTP_BAD_REQUEST) { + System.out.printf("Error response from %s: %d\n", httpUrl, statusCode); + } + } finally { + conn.disconnect(); + } + } + + final static private void writeTile( + final BufferedImage img, + final OutputStream outputStream, final String format, final float quality ) throws IOException { - new File( path ).getParentFile().mkdirs(); final ImageWriter writer = ImageIO.getImageWritersByFormatName( format ).next(); - final FileImageOutputStream output = new FileImageOutputStream( new File( path ) ); - writer.setOutput( output ); + ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream); + writer.setOutput(ios); if ( format.equalsIgnoreCase( "jpg" ) ) { final ImageWriteParam param = writer.getDefaultWriteParam(); @@ -76,9 +133,11 @@ final static public void writeTile( writer.write( null, new IIOImage( img.getRaster(), null, null ), param ); } else + { writer.write( img ); - + } + ios.flush(); writer.dispose(); - output.close(); } + } From 1953355a0072fe50b5466a6c99add10ae7079da7 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Mon, 16 May 2016 20:39:05 -0400 Subject: [PATCH 24/35] removed unused import --- src/main/java/org/catmaid/Util.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/catmaid/Util.java b/src/main/java/org/catmaid/Util.java index cfd1531..5f53a79 100644 --- a/src/main/java/org/catmaid/Util.java +++ b/src/main/java/org/catmaid/Util.java @@ -29,7 +29,6 @@ import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; -import javax.imageio.stream.FileImageOutputStream; import javax.imageio.stream.ImageOutputStream; /** From 31802769d4d131c449e5ae5f3713cb68330943a0 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Tue, 17 May 2016 14:20:28 -0400 Subject: [PATCH 25/35] output error messages --- pom.xml | 4 ++-- src/main/java/org/catmaid/Util.java | 13 ++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 0a6cf5e..bc54461 100644 --- a/pom.xml +++ b/pom.xml @@ -35,8 +35,8 @@ maven-compiler-plugin 2.5 - 1.6 - 1.6 + 1.7 + 1.7 diff --git a/src/main/java/org/catmaid/Util.java b/src/main/java/org/catmaid/Util.java index 5f53a79..899b807 100644 --- a/src/main/java/org/catmaid/Util.java +++ b/src/main/java/org/catmaid/Util.java @@ -18,9 +18,11 @@ import java.awt.Image; import java.awt.image.BufferedImage; +import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; @@ -108,8 +110,16 @@ final static private void writeTileToUrl( writeTile(img, os, format, quality); int statusCode = conn.getResponseCode(); if (statusCode >= HttpURLConnection.HTTP_BAD_REQUEST) { - System.out.printf("Error response from %s: %d\n", httpUrl, statusCode); + System.err.printf("Error response from %s: %d\n", httpUrl, statusCode); } + BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream()))); + String serverOutput; + while ((serverOutput = br.readLine()) != null) { + System.out.println(serverOutput); + } + } catch (IOException e) { + System.err.printf("Error writing to %s %d\n", httpUrl, conn.getExpiration()); + throw e; } finally { conn.disconnect(); } @@ -136,6 +146,7 @@ final static private void writeTile( writer.write( img ); } ios.flush(); + outputStream.flush(); writer.dispose(); } From 5a46b838cf3380e96ffe59c44cc95711cc6ab8cf Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Wed, 18 May 2016 22:38:14 -0400 Subject: [PATCH 26/35] change scaler to read from file or url --- src/main/java/org/catmaid/ScaleCATMAID.java | 25 +++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/catmaid/ScaleCATMAID.java b/src/main/java/org/catmaid/ScaleCATMAID.java index ef9f6e8..fc6bf3b 100644 --- a/src/main/java/org/catmaid/ScaleCATMAID.java +++ b/src/main/java/org/catmaid/ScaleCATMAID.java @@ -23,6 +23,7 @@ import java.awt.image.PixelGrabber; import java.io.File; import java.io.IOException; +import java.net.URL; import javax.imageio.ImageIO; @@ -131,24 +132,31 @@ static protected Param parseParameters() { } final static protected BufferedImage open( - final String path, + final String urlString, final BufferedImage alternative, final int type ) { - final File file = new File( path ); - if ( file.exists() ) + File f = new File( urlString ); + if ( f.exists() ) { try { - return ImageIO.read( new File( path ) ); + return ImageIO.read( new File( urlString ) ); } - catch ( final IOException e ) + catch ( IOException e ) + { + } + } else + { + try { + final URL url = new URL( urlString ); + return ImageIO.read( url ); + } + catch ( IOException e ) { - return alternative; } } - else - return alternative; + return alternative; } /** @@ -286,7 +294,6 @@ final public static void scale( if (notEmpty || !ignoreEmptyTiles) { target.getRaster().setDataElements( 0, 0, tileWidth, tileHeight, targetPixels ); final BufferedImage targetCopy = Util.draw( target, type ); - Util.writeTile( targetCopy, String.format( tileFormat, s, scale, x * iScale, y * iScale, z, tileWidth * iScale, tileHeight * iScale, yt, xt ), From 53fde3d9196f7ac4ebe98fdeeb9a1555158cc740 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Thu, 19 May 2016 00:37:17 -0400 Subject: [PATCH 27/35] don't attempt to read image if status is not OK --- src/main/java/org/catmaid/ScaleCATMAID.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/catmaid/ScaleCATMAID.java b/src/main/java/org/catmaid/ScaleCATMAID.java index fc6bf3b..cf8d120 100644 --- a/src/main/java/org/catmaid/ScaleCATMAID.java +++ b/src/main/java/org/catmaid/ScaleCATMAID.java @@ -23,6 +23,8 @@ import java.awt.image.PixelGrabber; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; import java.net.URL; import javax.imageio.ImageIO; @@ -145,15 +147,25 @@ final static protected BufferedImage open( } catch ( IOException e ) { + e.printStackTrace(); } } else { try { final URL url = new URL( urlString ); - return ImageIO.read( url ); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(false); + conn.setDoInput(true); + conn.setRequestMethod("GET"); + int statusCode = conn.getResponseCode(); + if (statusCode != HttpURLConnection.HTTP_OK) { + return alternative; + } + return ImageIO.read(conn.getInputStream()); } catch ( IOException e ) { + e.printStackTrace(); } } return alternative; From c5f7b19d529e33f9231b09ad378cfe6e29b22c93 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Sun, 22 May 2016 11:29:39 -0400 Subject: [PATCH 28/35] moved the tile reading to Utils --- src/main/java/org/catmaid/ScaleCATMAID.java | 65 +++------------------ src/main/java/org/catmaid/Util.java | 64 ++++++++++++++++---- 2 files changed, 62 insertions(+), 67 deletions(-) diff --git a/src/main/java/org/catmaid/ScaleCATMAID.java b/src/main/java/org/catmaid/ScaleCATMAID.java index cf8d120..aa8d5a3 100644 --- a/src/main/java/org/catmaid/ScaleCATMAID.java +++ b/src/main/java/org/catmaid/ScaleCATMAID.java @@ -21,13 +21,6 @@ import java.awt.Image; import java.awt.image.BufferedImage; import java.awt.image.PixelGrabber; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; - -import javax.imageio.ImageIO; /** *

A standalone command line application to generate the scale pyramid of an @@ -133,44 +126,6 @@ static protected Param parseParameters() { return p; } - final static protected BufferedImage open( - final String urlString, - final BufferedImage alternative, - final int type ) - { - File f = new File( urlString ); - if ( f.exists() ) - { - try - { - return ImageIO.read( new File( urlString ) ); - } - catch ( IOException e ) - { - e.printStackTrace(); - } - } else - { - try { - final URL url = new URL( urlString ); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setDoOutput(false); - conn.setDoInput(true); - conn.setRequestMethod("GET"); - int statusCode = conn.getResponseCode(); - if (statusCode != HttpURLConnection.HTTP_OK) { - return alternative; - } - return ImageIO.read(conn.getInputStream()); - } - catch ( IOException e ) - { - e.printStackTrace(); - } - } - return alternative; - } - /** * Generate scaled tiles from a range of an existing scale level 0 tile * stack. @@ -251,10 +206,9 @@ final public static void scale( } nResultTiles++; final long xt = x / (2 * tileWidth); - final Image imp1 = open( + final Image imp1 = Util.readTile( String.format( tileFormat, s1, scale1, x * iScale1, y * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt, 2 * xt ), - alternative, - type ); + alternative); if (maxX < 0) { if (imp1 == alternative) { @@ -267,27 +221,24 @@ final public static void scale( continue Y; } } - final Image imp2 = open( + final Image imp2 = Util.readTile( String.format( tileFormat, s1, scale1, ( x + tileWidth ) * iScale1, y * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt, 2 * xt + 1 ), - alternative, - type ); + alternative); proceedX = maxX >= 0 || imp2 != alternative; - final Image imp3 = open( + final Image imp3 = Util.readTile( String.format( tileFormat, s1, scale1, x * iScale1, ( y + tileHeight ) * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt + 1, 2 * xt ), - alternative, - type ); + alternative); proceedY = maxY >= 0 || imp3 != alternative; if (!proceedX && !proceedY && x == minX / iScale1 && y == minY / iScale1) { break S; } - final Image imp4 = open( + final Image imp4 = Util.readTile( String.format( tileFormat, s1, scale1, ( x + tileWidth ) * iScale1, ( y + tileHeight ) * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt + 1, 2 * xt + 1 ), - alternative, - type ); + alternative); if (imp1 == alternative && imp2 == alternative && imp3 == alternative && imp4 == alternative) { continue; diff --git a/src/main/java/org/catmaid/Util.java b/src/main/java/org/catmaid/Util.java index 899b807..6610104 100644 --- a/src/main/java/org/catmaid/Util.java +++ b/src/main/java/org/catmaid/Util.java @@ -38,9 +38,8 @@ * * @author Stephan Saalfeld */ -public class Util -{ - final static public String tilePath( +class Util { + final static String tilePath( final String tileFormat, final int scaleLevel, final double scale, @@ -50,21 +49,66 @@ final static public String tilePath( final int tileWidth, final int tileHeight, final long row, - final long column ) - { + final long column) { return String.format( tileFormat, scaleLevel, scale, x, y, z, tileWidth, tileHeight, row, column ); } - - final static public BufferedImage draw( + + final static BufferedImage draw( final Image img, - final int type ) - { + final int type) { final BufferedImage imgCopy = new BufferedImage( img.getWidth( null ), img.getHeight( null ), type ); imgCopy.createGraphics().drawImage( img, 0, 0, null ); return imgCopy; } - final static public void writeTile( + final static BufferedImage readTile( + final String url, + final BufferedImage alternative) { + if ( url.startsWith("file://") ) { + return readTileFromFile(url.substring("file://".length()), alternative); + } else if ( url.startsWith("http://") || url.startsWith("https://") ) { + return readTileFromUrl(url, alternative); + } else { + return readTileFromFile(url, alternative); + } + } + + final static BufferedImage readTileFromFile( + final String url, + final BufferedImage alternative) { + File f = new File( url ); + if ( f.exists() ) { + try { + return ImageIO.read( new File( url ) ); + } catch ( IOException e ) { + e.printStackTrace(); + } + } + return alternative; + } + + final static BufferedImage readTileFromUrl( + final String urlString, + final BufferedImage alternative) { + try { + final URL url = new URL( urlString ); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(false); + conn.setDoInput(true); + conn.setRequestMethod("GET"); + int statusCode = conn.getResponseCode(); + if (statusCode != HttpURLConnection.HTTP_OK) { + return alternative; + } + return ImageIO.read(conn.getInputStream()); + } catch ( IOException e ) + { + e.printStackTrace(); + } + return alternative; + } + + final static void writeTile( final BufferedImage img, final String url, final String format, From 70443fbcd1a1464ba5795bb0d9cec83bb8631798 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Thu, 2 Jun 2016 15:23:28 -0400 Subject: [PATCH 29/35] added scale level to the print statement --- .../java/org/catmaid/CATMAIDRandomAccessibleInterval.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index 56d80a3..e43935f 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -682,7 +682,7 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) final int[] pixels = new int[ tileWidth * tileHeight ]; try { - System.out.println( "Load r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); + System.out.println( "Load s=" + scale + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); final URL url = new URL( urlString ); final BufferedImage jpg = ImageIO.read( url ); @@ -697,11 +697,11 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) pg.grabPixels(); cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) ); - System.out.println( "Successfully loaded r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); + System.out.println( "Successfully loaded s=" + scale + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); } catch (final IOException e) { - System.out.println( "Failed loading r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); + System.out.println( "Failed loading s=" + scale + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) ); } catch (final InterruptedException e) From 614bd6d1f8055e8de3d4bb1869e5e5cb539d442b Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Thu, 2 Jun 2016 22:20:44 -0400 Subject: [PATCH 30/35] close the connection on read --- src/main/java/org/catmaid/Util.java | 33 ++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/catmaid/Util.java b/src/main/java/org/catmaid/Util.java index 6610104..083e39e 100644 --- a/src/main/java/org/catmaid/Util.java +++ b/src/main/java/org/catmaid/Util.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; @@ -90,9 +91,11 @@ final static BufferedImage readTileFromFile( final static BufferedImage readTileFromUrl( final String urlString, final BufferedImage alternative) { + HttpURLConnection conn = null; + InputStream connInputStream = null; try { final URL url = new URL( urlString ); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn = (HttpURLConnection) url.openConnection(); conn.setDoOutput(false); conn.setDoInput(true); conn.setRequestMethod("GET"); @@ -100,10 +103,21 @@ final static BufferedImage readTileFromUrl( if (statusCode != HttpURLConnection.HTTP_OK) { return alternative; } - return ImageIO.read(conn.getInputStream()); - } catch ( IOException e ) - { + connInputStream = conn.getInputStream(); + return ImageIO.read(connInputStream); + } catch ( IOException e ) { e.printStackTrace(); + } finally { + if (connInputStream != null) { + try { + connInputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (conn != null) { + conn.disconnect(); + } } return alternative; } @@ -150,13 +164,15 @@ final static private void writeTileToUrl( conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/octet-stream"); OutputStream os = conn.getOutputStream(); + InputStream is = null; try { writeTile(img, os, format, quality); int statusCode = conn.getResponseCode(); if (statusCode >= HttpURLConnection.HTTP_BAD_REQUEST) { System.err.printf("Error response from %s: %d\n", httpUrl, statusCode); } - BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream()))); + is = conn.getInputStream(); + BufferedReader br = new BufferedReader(new InputStreamReader((is))); String serverOutput; while ((serverOutput = br.readLine()) != null) { System.out.println(serverOutput); @@ -165,6 +181,13 @@ final static private void writeTileToUrl( System.err.printf("Error writing to %s %d\n", httpUrl, conn.getExpiration()); throw e; } finally { + if (is != null) { + try { + is.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } conn.disconnect(); } } From cc9fd22a1fbf5f970c791d762ecf7bd7bd3a5a14 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Fri, 3 Jun 2016 14:00:05 -0400 Subject: [PATCH 31/35] print the zoom level --- .../java/org/catmaid/CATMAIDRandomAccessibleInterval.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index e43935f..12e6330 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -682,7 +682,7 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) final int[] pixels = new int[ tileWidth * tileHeight ]; try { - System.out.println( "Load s=" + scale + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); + System.out.println( "Load s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); final URL url = new URL( urlString ); final BufferedImage jpg = ImageIO.read( url ); @@ -697,11 +697,11 @@ protected int[] fetchPixels2( final long r, final long c, final long z ) pg.grabPixels(); cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) ); - System.out.println( "Successfully loaded s=" + scale + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); + System.out.println( "Successfully loaded s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); } catch (final IOException e) { - System.out.println( "Failed loading s=" + scale + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); + System.out.println( "Failed loading s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) ); } catch (final InterruptedException e) From 112d07926c2ce879237a6ec2e5d3f1b81f594113 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Fri, 3 Jun 2016 17:58:14 -0400 Subject: [PATCH 32/35] make the orientation not dependent of the order --- src/main/java/org/catmaid/TileCATMAID.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index 4e954e7..e827d87 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -257,7 +257,7 @@ static private Param parseParameters() ); final Interval orientedScaledInterval; - if ( orientation.equalsIgnoreCase( "xz" ) ) + if ( orientation.equalsIgnoreCase( "xz" ) || orientation.equalsIgnoreCase( "zx" ) ) { p.orientation = Orientation.XZ; orientedScaledInterval = new FinalInterval( @@ -273,7 +273,7 @@ static private Param parseParameters() } ); } - else if ( orientation.equalsIgnoreCase( "zy" ) ) + else if ( orientation.equalsIgnoreCase( "zy" ) || orientation.equalsIgnoreCase( "yz" ) ) { p.orientation = Orientation.ZY; orientedScaledInterval = new FinalInterval( From d55c7a5285375ce1f4dc0016275eb01d4e5c4154 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Thu, 30 Jun 2016 11:27:39 -0400 Subject: [PATCH 33/35] added guava cache as the previous cache based on linkedhashmap didn't really work --- pom.xml | 8 +- .../CATMAIDRandomAccessibleInterval.java | 114 +++++++----------- src/main/java/org/catmaid/TileCATMAID.java | 1 - 3 files changed, 52 insertions(+), 71 deletions(-) diff --git a/pom.xml b/pom.xml index bc54461..3de7c81 100644 --- a/pom.xml +++ b/pom.xml @@ -22,11 +22,17 @@ imglib2 2.0.0-SNAPSHOT - + net.imglib2 imglib2-realtransform 2.0.0-SNAPSHOT + + com.google.guava + guava + 19.0 + + install diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index 12e6330..07ac008 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -44,9 +44,14 @@ import java.net.URL; import java.util.LinkedHashMap; import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; import javax.imageio.ImageIO; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + import net.imglib2.AbstractInterval; import net.imglib2.AbstractLocalizable; import net.imglib2.Interval; @@ -123,28 +128,17 @@ public int hashCode() { return ( int )( value ^ ( value >>> 32 ) ); } } - + class Entry { - final protected Key key; - final protected int[] data; + final int[] data; - public Entry( final Key key, final int[] data ) + public Entry( final int[] data ) { - this.key = key; this.data = data; } - - @Override - public void finalize() - { - synchronized ( cache ) - { - cache.remove( key ); - } - } } - + public class CATMAIDRandomAccess extends AbstractLocalizable implements RandomAccess< ARGBType > { protected long r, c; @@ -592,7 +586,7 @@ public CATMAIDRandomAccess copyRandomAccess() private static final int MAX_CACHE_SIZE = 2048; - final private Map< Key, SoftReference< Entry > > cache; + final private Cache< Key, Entry > tileCache; final private String urlFormat; final private long rows, cols, s; final private int tileWidth, tileHeight; @@ -619,18 +613,11 @@ public CATMAIDRandomAccessibleInterval( max[ 0 ] = ( long )( width * scale ) - 1; max[ 1 ] = ( long )( height * scale ) - 1; max[ 2 ] = depth - 1; - cache = - new LinkedHashMap> ( - (cacheSize > 0 ? cacheSize : MAX_CACHE_SIZE) * 10/7, - 0.7f, - true) { - private static final long serialVersionUID = 1L; - - @Override - protected boolean removeEldestEntry(Map.Entry> eldest) { - return size() > MAX_CACHE_SIZE; - } - }; + tileCache = CacheBuilder.newBuilder() + .maximumSize(cacheSize > 0 ? cacheSize : MAX_CACHE_SIZE) + .weakKeys() + .weakValues() + .build(); } @Override @@ -666,49 +653,38 @@ protected int[] fetchPixels( final long r, final long c, final long z ) protected int[] fetchPixels2( final long r, final long c, final long z ) { + Entry tileEntry = null; final Key key = new Key( r, c, z ); - synchronized ( cache ) - { - final SoftReference< Entry > cachedReference = cache.get( key ); - if ( cachedReference != null ) - { - final Entry cachedEntry = cachedReference.get(); - if ( cachedEntry != null ) - return cachedEntry.data; - } - - final String urlString = String.format( urlFormat, s, scale, c * tileWidth, r * tileHeight, z, tileWidth, tileHeight, r, c ); - - final int[] pixels = new int[ tileWidth * tileHeight ]; - try - { - System.out.println( "Load s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); - final URL url = new URL( urlString ); - final BufferedImage jpg = ImageIO.read( url ); - - /* This gymnastic is necessary to get reproducible gray - * values, just opening a JPG or PNG, even when saved by - * ImageIO, and grabbing its pixels results in gray values - * with a non-matching gamma transfer function, I cannot tell - * why... */ - final BufferedImage image = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); - image.createGraphics().drawImage( jpg, 0, 0, null ); - final PixelGrabber pg = new PixelGrabber( image, 0, 0, tileWidth, tileHeight, pixels, 0, tileWidth ); - pg.grabPixels(); + try { + tileEntry = tileCache.get(key, new Callable() { + @Override + public Entry call() { + final String urlString = String.format( urlFormat, s, scale, c * tileWidth, r * tileHeight, z, tileWidth, tileHeight, r, c ); + final int[] pixels = new int[ tileWidth * tileHeight ]; + try { + System.out.println( "Load s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); + final URL url = new URL( urlString ); + final BufferedImage jpg = ImageIO.read( url ); - cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) ); - System.out.println( "Successfully loaded s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); - } - catch (final IOException e) - { - System.out.println( "Failed loading s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); - cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) ); - } - catch (final InterruptedException e) - { - e.printStackTrace(); - } - return pixels; + /* This gymnastic is necessary to get reproducible gray + * values, just opening a JPG or PNG, even when saved by + * ImageIO, and grabbing its pixels results in gray values + * with a non-matching gamma transfer function, I cannot tell + * why... */ + final BufferedImage image = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB ); + image.createGraphics().drawImage( jpg, 0, 0, null ); + final PixelGrabber pg = new PixelGrabber( image, 0, 0, tileWidth, tileHeight, pixels, 0, tileWidth ); + pg.grabPixels(); + System.out.println( "Successfully loaded s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); + } catch (final Exception e) { + System.out.println( "Failed loading s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" ); + } + return new Entry(pixels); + } + }); + } catch (ExecutionException ee) { + ee.printStackTrace(); } + return tileEntry != null ? tileEntry.data : null; } } diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java index e827d87..d0ecb88 100644 --- a/src/main/java/org/catmaid/TileCATMAID.java +++ b/src/main/java/org/catmaid/TileCATMAID.java @@ -36,7 +36,6 @@ import org.catmaid.Tiler.Orientation; - /** *

A standalone command line application to export image tiles representing * scale level 0 of the tiled scale pyramids for the CATMAID interface from From a7351fed68222021a3975d9d05ab862a990b8923 Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Thu, 30 Jun 2016 11:42:11 -0400 Subject: [PATCH 34/35] removed unnecessary imports --- .../java/org/catmaid/CATMAIDRandomAccessibleInterval.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index 07ac008..3b54852 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -39,11 +39,7 @@ import java.awt.image.BufferedImage; import java.awt.image.PixelGrabber; -import java.io.IOException; -import java.lang.ref.SoftReference; import java.net.URL; -import java.util.LinkedHashMap; -import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; From 1e735c6134d4c6d5ca8fe205c7873471fdb830fe Mon Sep 17 00:00:00 2001 From: Cristian Goina Date: Thu, 30 Jun 2016 13:32:23 -0400 Subject: [PATCH 35/35] removed the weak keys --- .../java/org/catmaid/CATMAIDRandomAccessibleInterval.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java index 3b54852..0154fb8 100644 --- a/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java +++ b/src/main/java/org/catmaid/CATMAIDRandomAccessibleInterval.java @@ -611,11 +611,10 @@ public CATMAIDRandomAccessibleInterval( max[ 2 ] = depth - 1; tileCache = CacheBuilder.newBuilder() .maximumSize(cacheSize > 0 ? cacheSize : MAX_CACHE_SIZE) - .weakKeys() .weakValues() .build(); } - + @Override public int numDimensions() { @@ -642,6 +641,7 @@ protected int[] fetchPixels( final long r, final long c, final long z ) } catch ( final OutOfMemoryError e ) { + System.err.println("Out of memory error while fetching tile (" + c + "," + r + "," + z + "). Trying to recover"); System.gc(); return fetchPixels2( r, c, z ); }