diff --git a/src/main/java/cz/it4i/qcmp/benchmark/Benchmark.java b/src/main/java/cz/it4i/qcmp/benchmark/Benchmark.java index 117259ddf6704a5c36f96730554c1a056aefee88..4012de9f9e49f7e5ddf274510fb8dcfd44d7e031 100644 --- a/src/main/java/cz/it4i/qcmp/benchmark/Benchmark.java +++ b/src/main/java/cz/it4i/qcmp/benchmark/Benchmark.java @@ -51,7 +51,7 @@ public class Benchmark extends BenchmarkBase { return; } - decompressOps.setInputDataInfo(new FileInputData(qcmpFilePath)); + decompressOps.setInputDataInfo(new FileInputData(qcmpFilePath, null)); final String decompressedFile = getFileNamePathIntoOutDir(String.format(QUANTIZED_FILE_TEMPLATE, options.getInputDataInfo().getPlaneIndex(), diff --git a/src/main/java/cz/it4i/qcmp/benchmark/BenchmarkBase.java b/src/main/java/cz/it4i/qcmp/benchmark/BenchmarkBase.java index 2e7cf835fcae750b43316e80823a8d43c33cfbc1..6fc7dabf844b60c0573eb749496efd8d2633020d 100644 --- a/src/main/java/cz/it4i/qcmp/benchmark/BenchmarkBase.java +++ b/src/main/java/cz/it4i/qcmp/benchmark/BenchmarkBase.java @@ -2,8 +2,8 @@ package cz.it4i.qcmp.benchmark; import cz.it4i.qcmp.cli.CompressionOptionsCLIParser; import cz.it4i.qcmp.compression.CompressionOptions; +import cz.it4i.qcmp.data.HyperStackDimensions; import cz.it4i.qcmp.data.ImageU16; -import cz.it4i.qcmp.data.V3i; import cz.it4i.qcmp.io.InputData; import cz.it4i.qcmp.io.RawDataIO; import cz.it4i.qcmp.quantization.QTrainIteration; @@ -26,7 +26,7 @@ abstract class BenchmarkBase { protected final String inputFile; protected final String outputDirectory; protected final int[] planes; - protected final V3i rawImageDims; + protected final HyperStackDimensions rawImageDims; protected final int codebookSize; protected final String cacheFolder; @@ -60,9 +60,8 @@ abstract class BenchmarkBase { this.planes[i] = from + i; } } else { - final int planeCount = ifi.getDimensions().getZ(); - this.planes = new int[planeCount]; - for (int i = 0; i < planeCount; i++) { + this.planes = new int[ifi.getDimensions().getPlaneCount()]; + for (int i = 0; i < ifi.getDimensions().getPlaneCount(); i++) { this.planes[i] = i; } } @@ -118,11 +117,11 @@ abstract class BenchmarkBase { * @return True if file was saved. */ protected boolean saveQuantizedPlaneData(final int[] data, final String filename) { - final ImageU16 img = new ImageU16(rawImageDims.getX(), rawImageDims.getY(), data); + final ImageU16 img = new ImageU16(rawImageDims.getWidth(), rawImageDims.getHeight(), data); try { // NOTE(Moravec): Use big endian so that FIJI can read the image. RawDataIO.writeImageU16(getFileNamePathIntoOutDir(filename), img, false); - System.out.println(String.format("Saved %s", filename)); + System.out.printf("Saved %s\n", filename); } catch (final Exception e) { e.printStackTrace(); return false; @@ -146,8 +145,8 @@ abstract class BenchmarkBase { final String diffFilePath = getFileNamePathIntoOutDir(diffFile); final String absDiffFilePath = getFileNamePathIntoOutDir(absDiffFile); - final ImageU16 img = new ImageU16(rawImageDims.getX(), - rawImageDims.getY(), + final ImageU16 img = new ImageU16(rawImageDims.getWidth(), + rawImageDims.getHeight(), absDifferenceData); try { // NOTE(Moravec): Use little endian so that gnuplot can read the array. diff --git a/src/main/java/cz/it4i/qcmp/benchmark/SQBenchmark.java b/src/main/java/cz/it4i/qcmp/benchmark/SQBenchmark.java index a90c39df9e4534578e3a5e16539ca96818c702b5..5d99107ca84674d8bf564c85f938b06287cf58eb 100644 --- a/src/main/java/cz/it4i/qcmp/benchmark/SQBenchmark.java +++ b/src/main/java/cz/it4i/qcmp/benchmark/SQBenchmark.java @@ -54,7 +54,7 @@ public class SQBenchmark extends BenchmarkBase { quantizer = new ScalarQuantizer(codebook); System.out.println("Created quantizer from cache"); } else if (options.getCodebookType() == CompressionOptions.CodebookType.MiddlePlane) { - final int middlePlaneIndex = rawImageDims.getZ() / 2; + final int middlePlaneIndex = rawImageDims.getPlaneCount() / 2; final int[] middlePlaneData; try { diff --git a/src/main/java/cz/it4i/qcmp/benchmark/VQBenchmark.java b/src/main/java/cz/it4i/qcmp/benchmark/VQBenchmark.java index 33e0a361be7dc68fc882ad89624fde17234caf5f..f595914ff789e54adea975a46a85b6b0d2c7e340 100644 --- a/src/main/java/cz/it4i/qcmp/benchmark/VQBenchmark.java +++ b/src/main/java/cz/it4i/qcmp/benchmark/VQBenchmark.java @@ -19,7 +19,7 @@ public class VQBenchmark extends BenchmarkBase { private ImageU16 reconstructImageFromQuantizedVectors(final int[][] vectors, final V2i qVector) { - final Block reconstructedChunk = new Block(new V2i(rawImageDims.getX(), rawImageDims.getY())); + final Block reconstructedChunk = new Block(rawImageDims.getPlaneDimensions()); if (qVector.getY() > 1) { reconstructedChunk.reconstructFrom2DVectors(vectors, qVector); } else { diff --git a/src/main/java/cz/it4i/qcmp/cli/functions/EntropyCalculation.java b/src/main/java/cz/it4i/qcmp/cli/functions/EntropyCalculation.java index d58a61e5ed7d53a13972f2f767fb1bbb8213dd95..b01629a950fd026ef984ee28190c6f13e75f6742 100644 --- a/src/main/java/cz/it4i/qcmp/cli/functions/EntropyCalculation.java +++ b/src/main/java/cz/it4i/qcmp/cli/functions/EntropyCalculation.java @@ -36,7 +36,7 @@ public class EntropyCalculation extends CustomFunctionBase { reportWriter.write("Plane;Entropy\n"); - for (int planeIndex = 0; planeIndex < options.getInputDataInfo().getDimensions().getZ(); planeIndex++) { + for (int planeIndex = 0; planeIndex < options.getInputDataInfo().getDimensions().getPlaneCount(); planeIndex++) { final int[] planeData = loader.loadPlaneData(planeIndex); final double planeEntropy = Utils.calculateEntropy(planeData); diff --git a/src/main/java/cz/it4i/qcmp/cli/functions/MeasurePlaneErrorFunction.java b/src/main/java/cz/it4i/qcmp/cli/functions/MeasurePlaneErrorFunction.java index b3db0bca79bc5b2932a739b4d1599346ef41858b..9c6772a2a779a133419b54b0471c88982657f6cf 100644 --- a/src/main/java/cz/it4i/qcmp/cli/functions/MeasurePlaneErrorFunction.java +++ b/src/main/java/cz/it4i/qcmp/cli/functions/MeasurePlaneErrorFunction.java @@ -2,7 +2,7 @@ package cz.it4i.qcmp.cli.functions; import cz.it4i.qcmp.cli.CompressionOptionsCLIParser; import cz.it4i.qcmp.cli.CustomFunctionBase; -import cz.it4i.qcmp.data.V3i; +import cz.it4i.qcmp.data.HyperStackDimensions; import cz.it4i.qcmp.io.FileInputData; import cz.it4i.qcmp.io.loader.RawDataLoader; import cz.it4i.qcmp.utilities.Stopwatch; @@ -20,12 +20,10 @@ public class MeasurePlaneErrorFunction extends CustomFunctionBase { private final String OriginalFileForChannel0 = "D:\\biology\\tiff_data\\fused_tp_10_ch_0_16bit.raw"; private final String OriginalFileForChannel1 = "D:\\biology\\tiff_data\\fused_tp_10_ch_1_16bit.raw"; - private final V3i ReferenceFileDimensions = new V3i(1041, 996, 946); + private final HyperStackDimensions ReferenceFileDimensions = new HyperStackDimensions(1041, 996, 946); - private int[][] loadPlanes(final String srcFile, final V3i imageDims) throws IOException { - final FileInputData inputDataInfo = new FileInputData(srcFile); - inputDataInfo.setDimension(imageDims); - final RawDataLoader loader = new RawDataLoader(inputDataInfo); + private int[][] loadPlanes(final String srcFile, final HyperStackDimensions imageDims) throws IOException { + final RawDataLoader loader = new RawDataLoader(new FileInputData(srcFile, imageDims)); return loader.loadAllPlanesTo2DArray(); } @@ -132,10 +130,10 @@ public class MeasurePlaneErrorFunction extends CustomFunctionBase { reportWriter.write("=========================================\n"); reportWriter.write("PlaneIndex;ErrorSum;MeanError\n"); - final int planePixelCount = ReferenceFileDimensions.toV2i().multiplyTogether(); + final int planePixelCount = ReferenceFileDimensions.getNumberOfElementsInDimension(2); final int[] diffData = new int[planePixelCount]; - for (int plane = 0; plane < ReferenceFileDimensions.getZ(); plane++) { + for (int plane = 0; plane < ReferenceFileDimensions.getPlaneCount(); plane++) { Utils.differenceToArray(referenceData[plane], testData[plane], diffData); Utils.applyAbsFunction(diffData); diff --git a/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java b/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java index 2df7a95306a9114e5c99b6c0d0cf2fe3ca6eabf8..22b328d64310d8764bcc1b61f1cfa15909aecc02 100644 --- a/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java +++ b/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java @@ -119,7 +119,7 @@ public abstract class CompressorDecompressorBase { } return indices; } else { - return generateAllPlaneIndices(inputData.getDimensions().getZ()); + return generateAllPlaneIndices(inputData.getDimensions().getPlaneCount()); } } @@ -144,7 +144,7 @@ public abstract class CompressorDecompressorBase { * @return Index of the middle plane. */ protected int getMiddlePlaneIndex() { - return (options.getInputDataInfo().getDimensions().getZ() / 2); + return (options.getInputDataInfo().getDimensions().getPlaneCount() / 2); } /** diff --git a/src/main/java/cz/it4i/qcmp/compression/ImageCompressor.java b/src/main/java/cz/it4i/qcmp/compression/ImageCompressor.java index 61d5d45b5fdcd5e83f04004589f818736156d911..a7cd2ddac5a717c6007d7f0fe1e00ce166035544 100644 --- a/src/main/java/cz/it4i/qcmp/compression/ImageCompressor.java +++ b/src/main/java/cz/it4i/qcmp/compression/ImageCompressor.java @@ -131,7 +131,7 @@ public class ImageCompressor extends CompressorDecompressorBase { } duplicateAllListeners(imageCompressor); - long[] planeDataSizes = null; + final long[] planeDataSizes; try (final FileOutputStream fos = new FileOutputStream(options.getOutputFilePath(), false); final DataOutputStream compressStream = new DataOutputStream(new BufferedOutputStream(fos, 8192))) { @@ -193,7 +193,7 @@ public class ImageCompressor extends CompressorDecompressorBase { final Range<Integer> planeRange = options.getInputDataInfo().getPlaneRange(); return ((planeRange.getTo() + 1) - planeRange.getFrom()); } else { - return options.getInputDataInfo().getDimensions().getZ(); + return options.getInputDataInfo().getDimensions().getPlaneCount(); } } @@ -225,8 +225,8 @@ public class ImageCompressor extends CompressorDecompressorBase { header.setCodebookPerPlane(options.getCodebookType() == CompressionOptions.CodebookType.Individual); - header.setImageSizeX(options.getInputDataInfo().getDimensions().getX()); - header.setImageSizeY(options.getInputDataInfo().getDimensions().getY()); + header.setImageSizeX(options.getInputDataInfo().getDimensions().getWidth()); + header.setImageSizeY(options.getInputDataInfo().getDimensions().getHeight()); header.setImageSizeZ(getNumberOfPlanes()); header.setVectorDimension(options.getQuantizationVector()); diff --git a/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java b/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java index 78f9cbe214b3c8b1bc7c7ddabef02742b0f5c4b9..00ac7628818a6dd0371f380cae8955cd3ed0842b 100644 --- a/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java +++ b/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java @@ -203,7 +203,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm int[] trainData = null; if (options.getCodebookType() == CompressionOptions.CodebookType.MiddlePlane) { - final int middlePlaneIndex = inputDataInfo.getDimensions().getZ() / 2; + final int middlePlaneIndex = getMiddlePlaneIndex(); reportStatusToListeners("Loading single plane data."); trainData = planeLoader.loadPlaneData(middlePlaneIndex); } else if (inputDataInfo.isPlaneIndexSet()) { diff --git a/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java b/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java index 60182aabc588020639bb3d3b39a1029d1a7813af..2a064ebc40c98e83d14630b7feac63803c34bbae 100644 --- a/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java +++ b/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java @@ -185,9 +185,9 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm if (streamMode) { try { // Image dimensions - compressStream.writeShort(inputData.getDimensions().getX()); - compressStream.writeShort(inputData.getDimensions().getY()); - compressStream.writeShort(inputData.getDimensions().getZ()); + compressStream.writeShort(inputData.getDimensions().getWidth()); + compressStream.writeShort(inputData.getDimensions().getHeight()); + compressStream.writeShort(inputData.getDimensions().getPlaneCount()); // Write voxel layer in stream mode. compressStream.writeShort(planeIndices.length); @@ -266,13 +266,13 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm } final int voxelLayerDepth = options.getQuantizationVector().getZ(); - final int voxelLayerCount = calculateVoxelLayerCount(inputData.getDimensions().getZ(), voxelLayerDepth); + final int voxelLayerCount = calculateVoxelLayerCount(inputData.getDimensions().getPlaneCount(), voxelLayerDepth); if (streamMode) { try { // Image dimensions - compressStream.writeShort(inputData.getDimensions().getX()); - compressStream.writeShort(inputData.getDimensions().getY()); - compressStream.writeShort(inputData.getDimensions().getZ()); + compressStream.writeShort(inputData.getDimensions().getWidth()); + compressStream.writeShort(inputData.getDimensions().getHeight()); + compressStream.writeShort(inputData.getDimensions().getPlaneCount()); // Write voxel layer in stream mode. compressStream.writeShort(voxelLayerCount); @@ -294,7 +294,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm final int fromZ = (voxelLayerIndex * voxelLayerDepth); final int toZ = (voxelLayerIndex == voxelLayerCount - 1) - ? inputData.getDimensions().getZ() + ? inputData.getDimensions().getPlaneCount() : (voxelLayerDepth + (voxelLayerIndex * voxelLayerDepth)); assert (toZ >= fromZ); @@ -407,7 +407,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm int[][] loadDataForCodebookTraining(final IPlaneLoader planeLoader) throws ImageCompressionException { final int[][] trainingData; if (options.getCodebookType() == CompressionOptions.CodebookType.MiddlePlane) { - final int middlePlaneIndex = (options.getInputDataInfo().getDimensions().getZ() / 2); + final int middlePlaneIndex = getMiddlePlaneIndex(); trainingData = planeLoader.loadVectorsFromPlaneRange(options, new Range<>(middlePlaneIndex, middlePlaneIndex + 1)); } else if (options.getInputDataInfo().isPlaneIndexSet()) { reportStatusToListeners("VQ: Loading single plane data."); @@ -419,7 +419,8 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm } else { reportStatusToListeners("VQ: Loading all planes data."); trainingData = planeLoader.loadVectorsFromPlaneRange(options, - new Range<>(0, options.getInputDataInfo().getDimensions().getZ())); + new Range<>(0, + options.getInputDataInfo().getDimensions().getPlaneCount())); } return trainingData; } diff --git a/src/main/java/cz/it4i/qcmp/data/HyperStackDimensions.java b/src/main/java/cz/it4i/qcmp/data/HyperStackDimensions.java index 78a71be436c958544f02845ac3b66561f7581b29..101a5f5d2099fdc3a62a00558f22d7be5127296c 100644 --- a/src/main/java/cz/it4i/qcmp/data/HyperStackDimensions.java +++ b/src/main/java/cz/it4i/qcmp/data/HyperStackDimensions.java @@ -9,72 +9,107 @@ import java.util.Objects; public class HyperStackDimensions { private final int width; private final int height; - private final int sliceCount; + private final int planeCount; private final int numberOfTimepoints; /** * Create HyperStackDimensions. * - * @param width Width of the slice. - * @param height Height of the slice. - * @param sliceCount Slice count in the stack. + * @param width Width of the plane. + * @param height Height of the plane. + * @param planeCount Plane count in the stack. * @param numberOfTimepoints Number of stack timepoints. */ - public HyperStackDimensions(final int width, final int height, final int sliceCount, final int numberOfTimepoints) { + public HyperStackDimensions(final int width, final int height, final int planeCount, final int numberOfTimepoints) { this.width = width; this.height = height; - this.sliceCount = sliceCount; + this.planeCount = planeCount; this.numberOfTimepoints = numberOfTimepoints; } + /** + * Get number of elements in hyperstack with dimensionality = dimension. + * When calculating the element count, overflow is checked. This is because result of this + * function is usually used in places where we want to allocate memory. + * + * @param dimension Maximum dimension. + * @return Number of elements. + */ + @SuppressWarnings("DuplicateExpressions") + public int getNumberOfElementsInDimension(final int dimension) { + switch (dimension) { + case 1: + return width; + case 2: + return Math.multiplyExact(width, height); + case 3: + return Math.multiplyExact(planeCount, Math.multiplyExact(width, height)); + case 4: + return Math.multiplyExact(numberOfTimepoints, Math.multiplyExact(planeCount, Math.multiplyExact(width, height))); + default: + assert (false) : "Wrong dimension in getNumberOfElementsInDimension"; + return -1; + } + } + /** * Create HyperStackDimensions for single timepoint. * - * @param width Width of the slice. - * @param height Height of the slice. - * @param sliceCount Slice count in the stack. + * @param width Width of the plane. + * @param height Height of the plane. + * @param planeCount Plane count in the stack. */ - public HyperStackDimensions(final int width, final int height, final int sliceCount) { - this(width, height, sliceCount, 1); + public HyperStackDimensions(final int width, final int height, final int planeCount) { + this(width, height, planeCount, 1); } /** - * Create HyperStackDimensions for single slice and single timepoint. + * Create HyperStackDimensions for single plane and single timepoint. * - * @param width Width of the slice. - * @param height Height of the slice. + * @param width Width of the plane. + * @param height Height of the plane. */ public HyperStackDimensions(final int width, final int height) { this(width, height, 1, 1); } /** - * Get single slice width. (X) + * Get single plane width. (X) * - * @return Slice width. + * @return Plane width. */ public final int getWidth() { return width; } /** - * Get single slice height. (Y) + * Get single plane height. (Y) * - * @return Slice height. + * @return Plane height. */ public final int getHeight() { return height; } /** - * Get slice count. (Z, Plane Count) + * Get plane count. (Z) * - * @return Slice count. + * @return Plane count. */ - public final int getSliceCount() { - return sliceCount; + public final int getPlaneCount() { + return planeCount; } + /** + * Get dimensions of the single plane. + * + * @return Plane dimensions. + */ + public V2i getPlaneDimensions() { + return new V2i(width, height); + } + + /** * Get number of timepoints of the stack. * @@ -86,12 +121,12 @@ public class HyperStackDimensions { @Override public String toString() { - return String.format("X=%d;Y=%d;Z=%d;T=%d", width, height, sliceCount, numberOfTimepoints); + return String.format("X=%d;Y=%d;Z=%d;T=%d", width, height, planeCount, numberOfTimepoints); } @Override public int hashCode() { - return Objects.hash(width, height, sliceCount, numberOfTimepoints); + return Objects.hash(width, height, planeCount, numberOfTimepoints); } @Override @@ -99,7 +134,7 @@ public class HyperStackDimensions { if (obj instanceof HyperStackDimensions) { final HyperStackDimensions other = (HyperStackDimensions) obj; return (width == other.width && height == other.height && - sliceCount == other.sliceCount && numberOfTimepoints == other.numberOfTimepoints); + planeCount == other.planeCount && numberOfTimepoints == other.numberOfTimepoints); } return super.equals(obj); } diff --git a/src/main/java/cz/it4i/qcmp/data/V2i.java b/src/main/java/cz/it4i/qcmp/data/V2i.java index aca7fe528e3fe2be6e23cc62337c877f3afe5493..fa9a4862fbbd7e24d084f1ceb4cf438755a25b70 100644 --- a/src/main/java/cz/it4i/qcmp/data/V2i.java +++ b/src/main/java/cz/it4i/qcmp/data/V2i.java @@ -22,6 +22,6 @@ public final class V2i extends V2<Integer> { } public final int multiplyTogether() { - return getX() * getY(); + return Math.multiplyExact(getX(), getY()); } } diff --git a/src/main/java/cz/it4i/qcmp/data/V3i.java b/src/main/java/cz/it4i/qcmp/data/V3i.java index b75767215a4a956d37e55f27d9ed01be0c33908d..50d760cb96bab8567d20a884abb2c1ef6d542f03 100644 --- a/src/main/java/cz/it4i/qcmp/data/V3i.java +++ b/src/main/java/cz/it4i/qcmp/data/V3i.java @@ -32,7 +32,7 @@ public final class V3i extends V3<Integer> { return new V2i(getX(), getY()); } - public final long multiplyTogether() { - return ((long) getX() * (long) getY() * (long) getZ()); + public final int multiplyTogether() { + return Math.multiplyExact(getZ(), Math.multiplyExact(getX(), getY())); } } diff --git a/src/main/java/cz/it4i/qcmp/io/loader/CallbackLoader.java b/src/main/java/cz/it4i/qcmp/io/loader/CallbackLoader.java index 629ac238110453a8e7aacbf0ff7f34432fa3df1f..a6b370b8154b6997032504350a88101a49060e69 100644 --- a/src/main/java/cz/it4i/qcmp/io/loader/CallbackLoader.java +++ b/src/main/java/cz/it4i/qcmp/io/loader/CallbackLoader.java @@ -8,7 +8,7 @@ import cz.it4i.qcmp.io.CallbackInputData; import java.io.IOException; import java.util.Arrays; -public class CallbackLoader extends BasicLoader implements IPlaneLoader { +public class CallbackLoader extends GenericLoader implements IPlaneLoader { private final CallbackInputData callbackInputData; private final CallbackInputData.LoadCallback pixelLoad; @@ -27,12 +27,12 @@ public class CallbackLoader extends BasicLoader implements IPlaneLoader { @Override public int[] loadPlaneData(final int plane) { - final int planePixelCount = dims.getX() * dims.getY(); + final int planePixelCount = dims.getNumberOfElementsInDimension(2); final int[] planeData = new int[planePixelCount]; int index = 0; - for (int y = 0; y < dims.getY(); y++) { - for (int x = 0; x < dims.getX(); x++) { + for (int y = 0; y < dims.getHeight(); y++) { + for (int x = 0; x < dims.getWidth(); x++) { planeData[index++] = pixelLoad.getValueAt(x, y, plane); } } @@ -45,10 +45,10 @@ public class CallbackLoader extends BasicLoader implements IPlaneLoader { return new int[0]; } else if (planes.length == 1) { return loadPlaneData(planes[0]); - } else if (planes.length == dims.getZ()) { + } else if (planes.length == dims.getPlaneCount()) { return loadAllPlanesU16Data(); } - final int planePixelCount = dims.getX() * dims.getY(); + final int planePixelCount = dims.getNumberOfElementsInDimension(2); final long totalValueCount = (long) planePixelCount * (long) planes.length; if (totalValueCount > (long) Integer.MAX_VALUE) { throw new IOException("Unable to load image data for planes, file size is too big."); @@ -59,8 +59,8 @@ public class CallbackLoader extends BasicLoader implements IPlaneLoader { final int[] destBuffer = new int[(int) totalValueCount]; int index = 0; for (final int plane : planes) { - for (int y = 0; y < dims.getY(); y++) { - for (int x = 0; x < dims.getX(); x++) { + for (int y = 0; y < dims.getHeight(); y++) { + for (int x = 0; x < dims.getWidth(); x++) { destBuffer[index++] = pixelLoad.getValueAt(x, y, plane); } } @@ -69,17 +69,14 @@ public class CallbackLoader extends BasicLoader implements IPlaneLoader { } @Override - public int[] loadAllPlanesU16Data() throws IOException { - final long totalValueCount = dims.multiplyTogether(); - if (totalValueCount > (long) Integer.MAX_VALUE) { - throw new IOException("Unable to load all image data, file size is too big."); - } + public int[] loadAllPlanesU16Data() { + final long totalValueCount = dims.getNumberOfElementsInDimension(3); final int[] destBuffer = new int[(int) totalValueCount]; int index = 0; - for (int z = 0; z < dims.getZ(); z++) { - for (int y = 0; y < dims.getY(); y++) { - for (int x = 0; x < dims.getX(); x++) { + for (int z = 0; z < dims.getPlaneCount(); z++) { + for (int y = 0; y < dims.getHeight(); y++) { + for (int x = 0; x < dims.getWidth(); x++) { destBuffer[index++] = pixelLoad.getValueAt(x, y, z); } } diff --git a/src/main/java/cz/it4i/qcmp/io/loader/FlatBufferLoader.java b/src/main/java/cz/it4i/qcmp/io/loader/FlatBufferLoader.java index a5b60bb7760ce1da573da626625eeb9c6212cfc4..c580c0e62eecc88ee6e1fb2c7a8fa8f70db7dafa 100644 --- a/src/main/java/cz/it4i/qcmp/io/loader/FlatBufferLoader.java +++ b/src/main/java/cz/it4i/qcmp/io/loader/FlatBufferLoader.java @@ -13,7 +13,7 @@ import java.util.Arrays; /** * This loader is used when the entire dataset is stored in single buffer (array). */ -public class FlatBufferLoader extends BasicLoader implements IPlaneLoader { +public class FlatBufferLoader extends GenericLoader implements IPlaneLoader { /** * Flat buffer information. */ @@ -27,7 +27,7 @@ public class FlatBufferLoader extends BasicLoader implements IPlaneLoader { public FlatBufferLoader(final FlatBufferInputData bufferDataInfo) { super(bufferDataInfo.getDimensions()); this.bufferInputData = bufferDataInfo; - planePixelCount = dims.getX() * dims.getY(); + planePixelCount = dims.getNumberOfElementsInDimension(2); } @Override @@ -68,18 +68,15 @@ public class FlatBufferLoader extends BasicLoader implements IPlaneLoader { return new int[0]; } else if (planes.length == 1) { return loadPlaneData(planes[0]); - } else if (planes.length == bufferInputData.getDimensions().getZ()) { // Maybe? + } else if (planes.length == bufferInputData.getDimensions().getPlaneCount()) { return loadAllPlanesU16Data(); } - final long totalValueCount = (long) planePixelCount * (long) planes.length; - if (totalValueCount > (long) Integer.MAX_VALUE) { - throw new IOException("Unable to load image data for planes, file size is too big."); - } + final int totalValueCount = Math.multiplyExact(planePixelCount, planes.length); Arrays.sort(planes); final short[] flatBuffer = (short[]) bufferInputData.getPixelBuffer(); - final int[] destBuffer = new int[(int) totalValueCount]; + final int[] destBuffer = new int[totalValueCount]; int destOffset = 0; for (final int planeIndex : planes) { final int planeOffset = planeIndex * planePixelCount; diff --git a/src/main/java/cz/it4i/qcmp/io/loader/BasicLoader.java b/src/main/java/cz/it4i/qcmp/io/loader/GenericLoader.java similarity index 80% rename from src/main/java/cz/it4i/qcmp/io/loader/BasicLoader.java rename to src/main/java/cz/it4i/qcmp/io/loader/GenericLoader.java index a5bac1b035d88aac8927868dcee26f0f9a0a6150..8363538bf2dcf2809ebc5f4bd733045bece0d781 100644 --- a/src/main/java/cz/it4i/qcmp/io/loader/BasicLoader.java +++ b/src/main/java/cz/it4i/qcmp/io/loader/GenericLoader.java @@ -4,21 +4,20 @@ import cz.it4i.qcmp.data.*; import java.io.IOException; -public abstract class BasicLoader { - protected final V3i dims; +abstract class GenericLoader { + protected final HyperStackDimensions dims; protected int threadCount = 1; private DataWrappingStrategy wrappingStrategy = DataWrappingStrategy.MirroredRepeat; - protected BasicLoader(final V3i datasetDims) { + protected GenericLoader(final HyperStackDimensions datasetDims) { this.dims = datasetDims; } - public V3i getImageDimensions() { + public HyperStackDimensions getDatasetDimensions() { return dims; } - public DataWrappingStrategy getWrappingStrategy() { return wrappingStrategy; } @@ -37,19 +36,6 @@ public abstract class BasicLoader { */ public abstract int[] loadPlaneData(final int plane) throws IOException; - // /** - // * Read value from plane at specified offset. - // * - // * @param plane Zero based plane index. - // * @param offset Offset on flattened plane data. - // * @return Plane value at the index. - // */ - // protected int valueAt(final int plane, final int offset) { - // new Exception().printStackTrace(System.err); - // assert (false) : "Unimplemented overload of BasicLoader::valueAt()"; - // return Integer.MIN_VALUE; - // } - protected abstract int valueAt(final int plane, final int x, final int y, final int width); /** @@ -60,9 +46,9 @@ public abstract class BasicLoader { */ private int wrapColumnIndex(final int x) { if (wrappingStrategy == DataWrappingStrategy.ClampToEdge) { - return dims.getX() - 1; + return dims.getWidth() - 1; } else if (wrappingStrategy == DataWrappingStrategy.MirroredRepeat) { - return (dims.getX() - (1 + (x % dims.getX()))); + return (dims.getWidth() - (1 + (x % dims.getWidth()))); } return x; } @@ -75,9 +61,9 @@ public abstract class BasicLoader { */ private int wrapRowIndex(final int y) { if (wrappingStrategy == DataWrappingStrategy.ClampToEdge) { - return dims.getY() - 1; + return dims.getHeight() - 1; } else if (wrappingStrategy == DataWrappingStrategy.MirroredRepeat) { - return (dims.getY() - (1 + (y % dims.getY()))); + return (dims.getHeight() - (1 + (y % dims.getHeight()))); } return y; } @@ -90,17 +76,17 @@ public abstract class BasicLoader { */ private int wrapPlaneIndex(final int z) { if (wrappingStrategy == DataWrappingStrategy.ClampToEdge) { - return dims.getZ() - 1; + return dims.getPlaneCount() - 1; } else if (wrappingStrategy == DataWrappingStrategy.MirroredRepeat) { - return (dims.getZ() - (1 + (z % dims.getZ()))); + return (dims.getPlaneCount() - (1 + (z % dims.getPlaneCount()))); } return z; } protected int[][] loadRowVectorsImplByLoadPlaneData(final int vectorSize, final Range<Integer> planeRange) throws IOException { - final int rowVectorCount = (int) Math.ceil((double) dims.getX() / (double) vectorSize); + final int rowVectorCount = (int) Math.ceil((double) dims.getWidth() / (double) vectorSize); final int planeCount = planeRange.getTo() - planeRange.getFrom(); - final int vectorCount = planeCount * dims.getY() * rowVectorCount; + final int vectorCount = planeCount * dims.getHeight() * rowVectorCount; final int[][] rowVectors = new int[vectorCount][vectorSize]; int vectorIndex = 0; @@ -108,19 +94,19 @@ public abstract class BasicLoader { for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) { final int[] planeData = loadPlaneData(plane); - for (int row = 0; row < dims.getY(); row++) { + for (int row = 0; row < dims.getHeight(); row++) { for (int rowVectorIndex = 0; rowVectorIndex < rowVectorCount; rowVectorIndex++) { // Copy single vector. baseX = rowVectorIndex * vectorSize; for (int vectorX = 0; vectorX < vectorSize; vectorX++) { srcX = baseX + vectorX; - if (srcX >= dims.getX()) { + if (srcX >= dims.getWidth()) { if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) break; srcX = wrapColumnIndex(srcX); } - rowVectors[vectorIndex][vectorX] = planeData[Block.index(srcX, row, dims.getX())]; + rowVectors[vectorIndex][vectorX] = planeData[Block.index(srcX, row, dims.getWidth())]; } ++vectorIndex; } @@ -130,8 +116,8 @@ public abstract class BasicLoader { } protected int[][] loadRowVectorsImplByValueAt(final int vectorSize, final Range<Integer> planeRange) { - final int rowVectorCount = (int) Math.ceil((double) dims.getX() / (double) vectorSize); - final int vectorCount = dims.getZ() * dims.getY() * rowVectorCount; + final int rowVectorCount = (int) Math.ceil((double) dims.getWidth() / (double) vectorSize); + final int vectorCount = dims.getPlaneCount() * dims.getHeight() * rowVectorCount; final int[][] rowVectors = new int[vectorCount][vectorSize]; @@ -139,21 +125,21 @@ public abstract class BasicLoader { int baseX, srcX; for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) { - for (int row = 0; row < dims.getY(); row++) { + for (int row = 0; row < dims.getHeight(); row++) { for (int rowVectorIndex = 0; rowVectorIndex < rowVectorCount; rowVectorIndex++) { // Copy single vector. baseX = rowVectorIndex * vectorSize; for (int vectorX = 0; vectorX < vectorSize; vectorX++) { srcX = (baseX + vectorX); - if (srcX >= dims.getX()) { + if (srcX >= dims.getWidth()) { if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) break; srcX = wrapColumnIndex(srcX); } - // TODO(Moravec): dims.getY() should probably be dims.getX()! Check this! - rowVectors[vectorIndex][vectorX] = valueAt(plane, srcX, row, dims.getY()); + // TODO(Moravec): dims.getHeight() should probably be dims.getWidth()! Check this! + rowVectors[vectorIndex][vectorX] = valueAt(plane, srcX, row, dims.getHeight()); } ++vectorIndex; } @@ -165,15 +151,15 @@ public abstract class BasicLoader { protected int[][] loadBlocksImplByLoadPlaneData(final V2i blockDim, final Range<Integer> planeRange) throws IOException { final int blockSize = blockDim.multiplyTogether(); final int planeCount = planeRange.getTo() - planeRange.getFrom(); - final int blockCount = planeCount * Block.calculateRequiredChunkCount(dims.toV2i(), blockDim); + final int blockCount = planeCount * Block.calculateRequiredChunkCount(dims.getPlaneDimensions(), blockDim); final int[][] blocks = new int[blockCount][blockSize]; int blockIndex = 0; for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) { final int[] planeData = loadPlaneData(plane); - for (int blockYOffset = 0; blockYOffset < dims.getY(); blockYOffset += blockDim.getY()) { - for (int blockXOffset = 0; blockXOffset < dims.getX(); blockXOffset += blockDim.getX()) { + for (int blockYOffset = 0; blockYOffset < dims.getHeight(); blockYOffset += blockDim.getY()) { + for (int blockXOffset = 0; blockXOffset < dims.getWidth(); blockXOffset += blockDim.getX()) { loadBlock(blocks[blockIndex++], planeData, blockXOffset, blockYOffset, blockDim); } } @@ -184,14 +170,14 @@ public abstract class BasicLoader { protected int[][] loadBlocksImplByValueAt(final V2i blockDim, final Range<Integer> planeRange) { final int blockSize = blockDim.multiplyTogether(); final int planeCount = planeRange.getTo() - planeRange.getFrom(); - final int blockCount = planeCount * Block.calculateRequiredChunkCount(dims.toV2i(), blockDim); + final int blockCount = planeCount * Block.calculateRequiredChunkCount(dims.getPlaneDimensions(), blockDim); final int[][] blocks = new int[blockCount][blockSize]; int blockIndex = 0; for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) { - for (int blockYOffset = 0; blockYOffset < dims.getY(); blockYOffset += blockDim.getY()) { - for (int blockXOffset = 0; blockXOffset < dims.getX(); blockXOffset += blockDim.getX()) { + for (int blockYOffset = 0; blockYOffset < dims.getHeight(); blockYOffset += blockDim.getY()) { + for (int blockXOffset = 0; blockXOffset < dims.getWidth(); blockXOffset += blockDim.getX()) { loadBlock(blocks[blockIndex++], plane, blockXOffset, blockYOffset, blockDim); } } @@ -204,7 +190,7 @@ public abstract class BasicLoader { for (int y = 0; y < blockDim.getY(); y++) { srcY = blockYOffset + y; // Row overflow - if (srcY >= dims.getY()) { + if (srcY >= dims.getHeight()) { if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) { break; } @@ -215,25 +201,24 @@ public abstract class BasicLoader { srcX = blockXOffset + x; // Column overflow. - if (srcX >= dims.getX()) { + if (srcX >= dims.getWidth()) { if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) { break; } srcX = wrapColumnIndex(srcX); } - block[Block.index(x, y, blockDim.getX())] = valueAt(planeIndex, srcX, srcY, dims.getX()); + block[Block.index(x, y, blockDim.getX())] = valueAt(planeIndex, srcX, srcY, dims.getWidth()); } } } - private void loadBlock(final int[] block, final int[] planeData, final int blockXOffset, final int blockYOffset, final V2i blockDim) { int srcX, srcY; for (int y = 0; y < blockDim.getY(); y++) { srcY = blockYOffset + y; // Row overflow - if (srcY >= dims.getY()) { + if (srcY >= dims.getHeight()) { if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) { break; } @@ -242,14 +227,14 @@ public abstract class BasicLoader { for (int x = 0; x < blockDim.getX(); x++) { srcX = blockXOffset + x; // Column overflow. - if (srcX >= dims.getX()) { + if (srcX >= dims.getWidth()) { if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) { break; } srcX = wrapColumnIndex(srcX); } - block[Block.index(x, y, blockDim.getX())] = planeData[Block.index(srcX, srcY, dims.getX())]; + block[Block.index(x, y, blockDim.getX())] = planeData[Block.index(srcX, srcY, dims.getWidth())]; } } } @@ -259,7 +244,7 @@ public abstract class BasicLoader { for (int z = 0; z < voxelDim.getZ(); z++) { srcZ = voxelZOffset + z; - if (srcZ >= dims.getZ()) { + if (srcZ >= dims.getPlaneCount()) { // Handle plane overflow. if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) { break; @@ -270,7 +255,7 @@ public abstract class BasicLoader { for (int y = 0; y < voxelDim.getY(); y++) { srcY = voxelYOffset + y; - if (srcY >= dims.getY()) { + if (srcY >= dims.getHeight()) { // Handle row overflow. if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) { break; @@ -281,7 +266,7 @@ public abstract class BasicLoader { for (int x = 0; x < voxelDim.getX(); x++) { srcX = voxelXOffset + x; - if (srcX >= dims.getX()) { + if (srcX >= dims.getWidth()) { // Handle column overflow. if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) { break; @@ -289,7 +274,7 @@ public abstract class BasicLoader { srcX = wrapColumnIndex(srcX); } - voxel[Voxel.dataIndex(x, y, z, voxelDim)] = valueAt(srcZ, srcX, srcY, dims.getX()); + voxel[Voxel.dataIndex(x, y, z, voxelDim)] = valueAt(srcZ, srcX, srcY, dims.getWidth()); } } } @@ -306,7 +291,7 @@ public abstract class BasicLoader { for (int y = 0; y < voxelDim.getY(); y++) { srcY = voxelYOffset + y; - if (srcY >= dims.getY()) { + if (srcY >= dims.getHeight()) { // Handle row overflow. if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) { break; @@ -317,7 +302,7 @@ public abstract class BasicLoader { for (int x = 0; x < voxelDim.getX(); x++) { srcX = voxelXOffset + x; - if (srcX >= dims.getX()) { + if (srcX >= dims.getWidth()) { // Handle column overflow. if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) { break; @@ -325,7 +310,7 @@ public abstract class BasicLoader { srcX = wrapColumnIndex(srcX); } - voxel[Voxel.dataIndex(x, y, z, voxelDim)] = planesData[z][Block.index(srcX, srcY, dims.getX())]; + voxel[Voxel.dataIndex(x, y, z, voxelDim)] = planesData[z][Block.index(srcX, srcY, dims.getWidth())]; } } } @@ -339,9 +324,9 @@ public abstract class BasicLoader { * @return Allocated array. */ private int[][] allocateVoxelArray(final V3i voxelDim, final Range<Integer> planeRange) { - final int voxelElementCount = (int) voxelDim.multiplyTogether(); + final int voxelElementCount = voxelDim.multiplyTogether(); final int rangeSize = planeRange.getTo() - planeRange.getFrom(); - final V3i srcVoxel = new V3i(dims.getX(), dims.getY(), rangeSize); + final V3i srcVoxel = new V3i(dims.getWidth(), dims.getHeight(), rangeSize); final int voxelCount = Voxel.calculateRequiredVoxelCount(srcVoxel, voxelDim); return new int[voxelCount][voxelElementCount]; } @@ -359,8 +344,8 @@ public abstract class BasicLoader { int voxelIndex = 0; for (int voxelZOffset = planeRange.getFrom(); voxelZOffset < planeRange.getTo(); voxelZOffset += voxelDim.getZ()) { - for (int voxelYOffset = 0; voxelYOffset < dims.getY(); voxelYOffset += voxelDim.getY()) { - for (int voxelXOffset = 0; voxelXOffset < dims.getX(); voxelXOffset += voxelDim.getX()) { + for (int voxelYOffset = 0; voxelYOffset < dims.getHeight(); voxelYOffset += voxelDim.getY()) { + for (int voxelXOffset = 0; voxelXOffset < dims.getWidth(); voxelXOffset += voxelDim.getX()) { loadVoxel(voxels[voxelIndex++], voxelXOffset, voxelYOffset, voxelZOffset, voxelDim); } } @@ -370,16 +355,16 @@ public abstract class BasicLoader { private void preloadPlanesData(final int[][] planesData, final int planeOffset, final int count) throws IOException { for (int i = 0; i < count; i++) { - if (planeOffset + i < dims.getZ()) + if (planeOffset + i < dims.getPlaneCount()) planesData[i] = loadPlaneData(planeOffset + i); else { if (wrappingStrategy == DataWrappingStrategy.LeaveBlank) { - planesData[i] = new int[dims.toV2i().multiplyTogether()]; + planesData[i] = new int[dims.getWidth() * dims.getHeight()]; } else if (wrappingStrategy == DataWrappingStrategy.ClampToEdge) { - assert (i > 0) : "Overflow on the first plane of voxel???"; + // assert (i > 0) : "Overflow on the first plane of voxel???"; planesData[i] = planesData[i - 1]; } else if (wrappingStrategy == DataWrappingStrategy.MirroredRepeat) { - final int srcZ = dims.getZ() - (((planeOffset + i) - dims.getZ()) + 1); + final int srcZ = dims.getPlaneCount() - (((planeOffset + i) - dims.getPlaneCount()) + 1); planesData[i] = loadPlaneData(srcZ); } } @@ -404,8 +389,8 @@ public abstract class BasicLoader { preloadPlanesData(planesData, voxelZOffset, voxelDim.getZ()); - for (int voxelYOffset = 0; voxelYOffset < dims.getY(); voxelYOffset += voxelDim.getY()) { - for (int voxelXOffset = 0; voxelXOffset < dims.getX(); voxelXOffset += voxelDim.getX()) { + for (int voxelYOffset = 0; voxelYOffset < dims.getHeight(); voxelYOffset += voxelDim.getY()) { + for (int voxelXOffset = 0; voxelXOffset < dims.getWidth(); voxelXOffset += voxelDim.getX()) { loadVoxel(voxels[voxelIndex++], planesData, voxelXOffset, voxelYOffset, voxelDim); } } diff --git a/src/main/java/cz/it4i/qcmp/io/loader/IPlaneLoader.java b/src/main/java/cz/it4i/qcmp/io/loader/IPlaneLoader.java index a864ac62bfe7b8209ec06f69043634caf9363944..4db0090b33b9efa2c1e7028e8c1ba24e8f130685 100644 --- a/src/main/java/cz/it4i/qcmp/io/loader/IPlaneLoader.java +++ b/src/main/java/cz/it4i/qcmp/io/loader/IPlaneLoader.java @@ -2,6 +2,7 @@ package cz.it4i.qcmp.io.loader; import cz.it4i.qcmp.compression.CompressionOptions; import cz.it4i.qcmp.compression.exception.ImageCompressionException; +import cz.it4i.qcmp.data.HyperStackDimensions; import cz.it4i.qcmp.data.Range; import cz.it4i.qcmp.data.V2i; import cz.it4i.qcmp.data.V3i; @@ -41,7 +42,7 @@ public interface IPlaneLoader { * * @return Image of the loader image. */ - V3i getImageDimensions(); + HyperStackDimensions getDatasetDimensions(); /** * Load specified plane data. @@ -92,7 +93,7 @@ public interface IPlaneLoader { * @throws IOException When fails to load plane data. */ default int[][] loadRowVectors(final int vectorSize) throws IOException { - return loadRowVectors(vectorSize, new Range<>(0, getImageDimensions().getZ())); + return loadRowVectors(vectorSize, new Range<>(0, getDatasetDimensions().getPlaneCount())); } /** @@ -113,7 +114,7 @@ public interface IPlaneLoader { * @throws IOException When fails to load plane data. */ default int[][] loadBlocks(final V2i blockDim) throws IOException { - return loadBlocks(blockDim, new Range<>(0, getImageDimensions().getZ())); + return loadBlocks(blockDim, new Range<>(0, getDatasetDimensions().getPlaneCount())); } /** @@ -134,7 +135,7 @@ public interface IPlaneLoader { * @throws IOException when fails to load plane data. */ default int[][] loadVoxels(final V3i voxelDim) throws IOException { - return loadVoxels(voxelDim, new Range<>(0, getImageDimensions().getZ())); + return loadVoxels(voxelDim, new Range<>(0, getDatasetDimensions().getPlaneCount())); } /** diff --git a/src/main/java/cz/it4i/qcmp/io/loader/ImageJBufferLoader.java b/src/main/java/cz/it4i/qcmp/io/loader/ImageJBufferLoader.java index a0b8e7eb21759e5c539fc6a686c0cba4c5ccd7e4..e1769dde1288446d4e6c251a089628eda36d490e 100644 --- a/src/main/java/cz/it4i/qcmp/io/loader/ImageJBufferLoader.java +++ b/src/main/java/cz/it4i/qcmp/io/loader/ImageJBufferLoader.java @@ -5,20 +5,17 @@ import cz.it4i.qcmp.data.Range; import cz.it4i.qcmp.data.V2i; import cz.it4i.qcmp.data.V3i; import cz.it4i.qcmp.io.BufferInputData; -import cz.it4i.qcmp.io.InputData; import cz.it4i.qcmp.utilities.TypeConverter; import java.io.IOException; import java.util.Arrays; -public final class ImageJBufferLoader extends BasicLoader implements IPlaneLoader { +public final class ImageJBufferLoader extends GenericLoader implements IPlaneLoader { private final BufferInputData bufferInputData; public ImageJBufferLoader(final BufferInputData bufferDataInfo) { super(bufferDataInfo.getDimensions()); this.bufferInputData = bufferDataInfo; - // FIXME: Support more pixel types. - assert (this.bufferInputData.getPixelType() == InputData.PixelType.Gray16); } @Override @@ -37,9 +34,9 @@ public final class ImageJBufferLoader extends BasicLoader implements IPlaneLoade final short[] srcBuffer = (short[]) bufferInputData.getPixelBuffer(plane); return TypeConverter.shortArrayToIntArray(srcBuffer); } - + @Override - protected int valueAt(int plane, int x, int y, int width) { + protected int valueAt(final int plane, final int x, final int y, final int width) { return TypeConverter.shortToInt(((short[]) bufferInputData.getPixelBuffer(plane))[Block.index(x, y, width)]); } @@ -49,20 +46,15 @@ public final class ImageJBufferLoader extends BasicLoader implements IPlaneLoade return new int[0]; } else if (planes.length == 1) { return loadPlaneData(planes[0]); - } else if (planes.length == bufferInputData.getDimensions().getZ()) { // Maybe? + } else if (planes.length == dims.getPlaneCount()) { return loadAllPlanesU16Data(); } - final int planePixelCount = - bufferInputData.getDimensions().getX() * bufferInputData.getDimensions().getY(); - final long totalValueCount = (long) planePixelCount * (long) planes.length; - - if (totalValueCount > (long) Integer.MAX_VALUE) { - throw new IOException("Unable to load image data for planes, file size is too big."); - } + final int planePixelCount = dims.getNumberOfElementsInDimension(2); + final int totalValueCount = Math.multiplyExact(planePixelCount, planes.length); Arrays.sort(planes); - final int[] destBuffer = new int[(int) totalValueCount]; + final int[] destBuffer = new int[totalValueCount]; int destOffset = 0; for (final int planeIndex : planes) { final short[] srcBuffer = (short[]) bufferInputData.getPixelBuffer(planeIndex); @@ -74,17 +66,12 @@ public final class ImageJBufferLoader extends BasicLoader implements IPlaneLoade @Override public int[] loadAllPlanesU16Data() throws IOException { - final V3i imageDims = bufferInputData.getDimensions(); - final long totalValueCount = imageDims.multiplyTogether(); - final int planePixelCount = imageDims.getX() * imageDims.getY(); - - if (totalValueCount > (long) Integer.MAX_VALUE) { - throw new IOException("Unable to load all image data, file size is too big."); - } + final int planePixelCount = dims.getNumberOfElementsInDimension(2); + final int totalValueCount = dims.getNumberOfElementsInDimension(3); - final int[] destBuffer = new int[(int) totalValueCount]; + final int[] destBuffer = new int[totalValueCount]; int destOffset = 0; - for (int planeIndex = 0; planeIndex < imageDims.getZ(); planeIndex++) { + for (int planeIndex = 0; planeIndex < dims.getPlaneCount(); planeIndex++) { final short[] srcBuffer = (short[]) bufferInputData.getPixelBuffer(planeIndex); copyShortArrayIntoBuffer(srcBuffer, destBuffer, destOffset, planePixelCount); destOffset += planePixelCount; diff --git a/src/main/java/cz/it4i/qcmp/io/loader/RawDataLoader.java b/src/main/java/cz/it4i/qcmp/io/loader/RawDataLoader.java index 55f0e8595f62b7b7f8211a204cc5703ae273ba66..8d4834c2d0ddcfa39ed32d1d696185e794bb39ba 100644 --- a/src/main/java/cz/it4i/qcmp/io/loader/RawDataLoader.java +++ b/src/main/java/cz/it4i/qcmp/io/loader/RawDataLoader.java @@ -12,7 +12,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.util.Arrays; -public final class RawDataLoader extends BasicLoader implements IPlaneLoader { +public final class RawDataLoader extends GenericLoader implements IPlaneLoader { private final FileInputData inputDataInfo; private interface StorePlaneDataCallback { @@ -36,8 +36,8 @@ public final class RawDataLoader extends BasicLoader implements IPlaneLoader { final byte[] buffer; try (final FileInputStream fileStream = new FileInputStream(inputDataInfo.getFilePath())) { - final long planeSize = (long) dims.getX() * (long) dims.getY() * 2; - final long expectedFileSize = planeSize * dims.getZ(); + final long planeSize = dims.getNumberOfElementsInDimension(2) * 2; + final long expectedFileSize = planeSize * dims.getPlaneCount(); final long fileSize = fileStream.getChannel().size(); if (expectedFileSize != fileSize) { @@ -72,7 +72,7 @@ public final class RawDataLoader extends BasicLoader implements IPlaneLoader { storeCallback.store(0, loadPlaneData(planes[0])); } - final int planeValueCount = inputDataInfo.getDimensions().getX() * inputDataInfo.getDimensions().getY(); + final int planeValueCount = dims.getNumberOfElementsInDimension(2); final int planeDataSize = 2 * planeValueCount; final byte[] planeBuffer = new byte[planeDataSize]; @@ -117,13 +117,10 @@ public final class RawDataLoader extends BasicLoader implements IPlaneLoader { @Override public int[] loadPlanesU16Data(final int[] planes) throws IOException { + final int planeValueCount = dims.getNumberOfElementsInDimension(2); + final int totalValueCount = dims.getNumberOfElementsInDimension(3); - final int planeValueCount = inputDataInfo.getDimensions().getX() * inputDataInfo.getDimensions().getY(); - final long totalValueCount = (long) planeValueCount * planes.length; - if (totalValueCount > (long) Integer.MAX_VALUE) { - throw new IOException("Integer count is too big."); - } - final int[] data = new int[(int) totalValueCount]; + final int[] data = new int[totalValueCount]; loadPlanesU16DataImpl(planes, (index, planeData) -> { System.arraycopy(planeData, 0, data, (index * planeValueCount), planeValueCount); @@ -134,19 +131,16 @@ public final class RawDataLoader extends BasicLoader implements IPlaneLoader { @Override public int[] loadAllPlanesU16Data() throws IOException { - final V3i imageDims = inputDataInfo.getDimensions(); - final long dataSize = (long) imageDims.getX() * (long) imageDims.getY() * (long) imageDims.getZ(); + final int dataElementCount = dims.getNumberOfElementsInDimension(3); - if (dataSize > (long) Integer.MAX_VALUE) { - throw new IOException("RawFile size is too big."); - } - final int[] values = new int[(int) dataSize]; + final int[] values = new int[(int) dataElementCount]; + // TODO(Moravec): dis.readUnsignedShort() should be replaced with .read()! try (final FileInputStream fileStream = new FileInputStream(inputDataInfo.getFilePath()); final DataInputStream dis = new DataInputStream(new BufferedInputStream(fileStream, 8192))) { - for (int i = 0; i < (int) dataSize; i++) { + for (int i = 0; i < (int) dataElementCount; i++) { values[i] = dis.readUnsignedShort(); } } @@ -155,15 +149,14 @@ public final class RawDataLoader extends BasicLoader implements IPlaneLoader { } public int[][] loadAllPlanesTo2DArray() throws IOException { - final V3i imageDims = inputDataInfo.getDimensions(); - final int planePixelCount = imageDims.getX() * imageDims.getY(); + final int planePixelCount = dims.getNumberOfElementsInDimension(2); final int planeDataSize = planePixelCount * 2; - final int[][] result = new int[imageDims.getZ()][]; + final int[][] result = new int[dims.getPlaneCount()][]; final byte[] planeBuffer = new byte[planeDataSize]; try (final FileInputStream fileStream = new FileInputStream(inputDataInfo.getFilePath())) { - for (int plane = 0; plane < imageDims.getZ(); plane++) { + for (int plane = 0; plane < dims.getPlaneCount(); plane++) { int toRead = planeDataSize; while (toRead > 0) { final int read = fileStream.read(planeBuffer, planeDataSize - toRead, toRead); diff --git a/src/main/java/cz/it4i/qcmp/io/loader/SCIFIOLoader.java b/src/main/java/cz/it4i/qcmp/io/loader/SCIFIOLoader.java index a253532c640cdd23692cbfd6104815280f951911..2d0e8db1e112d9ad93cb45f24ab56e85cfbe8f98 100644 --- a/src/main/java/cz/it4i/qcmp/io/loader/SCIFIOLoader.java +++ b/src/main/java/cz/it4i/qcmp/io/loader/SCIFIOLoader.java @@ -12,7 +12,7 @@ import io.scif.Reader; import java.io.IOException; import java.util.Arrays; -public final class SCIFIOLoader extends BasicLoader implements IPlaneLoader { +public final class SCIFIOLoader extends GenericLoader implements IPlaneLoader { private final FileInputData inputDataInfo; private final Reader reader; @@ -55,7 +55,7 @@ public final class SCIFIOLoader extends BasicLoader implements IPlaneLoader { return loadPlaneData(planes[0]); } - final int planeValueCount = inputDataInfo.getDimensions().getX() * inputDataInfo.getDimensions().getY(); + final int planeValueCount = dims.getNumberOfElementsInDimension(2); final long planeDataSize = 2 * (long) planeValueCount; final long totalValueCount = (long) planeValueCount * planes.length; @@ -87,9 +87,8 @@ public final class SCIFIOLoader extends BasicLoader implements IPlaneLoader { @Override public int[] loadAllPlanesU16Data() throws IOException { - final V3i imageDims = inputDataInfo.getDimensions(); - final long planePixelCount = (long) imageDims.getX() * (long) imageDims.getY(); - final long dataSize = planePixelCount * (long) imageDims.getZ(); + final long planePixelCount = dims.getNumberOfElementsInDimension(2); + final long dataSize = planePixelCount * (long) dims.getPlaneCount(); if (dataSize > (long) Integer.MAX_VALUE) { throw new IOException("FileSize is too big."); @@ -97,7 +96,7 @@ public final class SCIFIOLoader extends BasicLoader implements IPlaneLoader { final int[] values = new int[(int) dataSize]; byte[] planeBytes; - for (int plane = 0; plane < imageDims.getZ(); plane++) { + for (int plane = 0; plane < dims.getPlaneCount(); plane++) { try { planeBytes = reader.openPlane(0, plane).getBytes(); } catch (final FormatException e) {