diff --git a/src/main/java/azgracompress/benchmark/BenchmarkBase.java b/src/main/java/azgracompress/benchmark/BenchmarkBase.java index 8e20bd7f21a9ced52e7a190fb169f937a4860d1d..622dadd9226fc445e6bde059c7978e24c5fef406 100644 --- a/src/main/java/azgracompress/benchmark/BenchmarkBase.java +++ b/src/main/java/azgracompress/benchmark/BenchmarkBase.java @@ -33,27 +33,11 @@ abstract class BenchmarkBase { protected final int workerCount; - protected BenchmarkBase(final String inputFile, - final String outputDirectory, - final int[] planes, - final V3i rawImageDims) { - this.inputFile = inputFile; - this.outputDirectory = outputDirectory; - this.planes = planes; - this.rawImageDims = rawImageDims; - - hasReferencePlane = false; - referencePlaneIndex = -1; - codebookSize = 256; - - hasCacheFolder = false; - cacheFolder = null; - hasGeneralQuantizer = false; - - workerCount = 1; - } + protected final ParsedCliOptions options; protected BenchmarkBase(final ParsedCliOptions options) { + this.options = options; + final InputFileInfo ifi = options.getInputFileInfo(); this.inputFile = ifi.getFilePath(); this.outputDirectory = options.getOutputFile(); @@ -98,32 +82,32 @@ abstract class BenchmarkBase { return file.getAbsolutePath(); } - /** - * Load u16 plane from RAW file. - * - * @param planeIndex Zero based plane index. - * @return u16 plane. - */ - protected ImageU16 loadPlane(final int planeIndex) { - try { - return RawDataIO.loadImageU16(inputFile, rawImageDims, planeIndex); - } catch (Exception ex) { - ex.printStackTrace(); - } - return null; - } - - /** - * Load U16 plane data from RAW file. - * - * @param planeIndex Zero based plane index. - * @return U16 array of image plane data. - */ - protected int[] loadPlaneData(final int planeIndex) { - ImageU16 plane = loadPlane(planeIndex); - - return (plane != null) ? plane.getData() : new int[0]; - } + // /** + // * Load u16 plane from RAW file. + // * + // * @param planeIndex Zero based plane index. + // * @return u16 plane. + // */ + // protected ImageU16 loadPlane(final int planeIndex) { + // try { + // return RawDataIO.loadImageU16(inputFile, rawImageDims, planeIndex); + // } catch (Exception ex) { + // ex.printStackTrace(); + // } + // return null; + // } + + // /** + // * Load U16 plane data from RAW file. + // * + // * @param planeIndex Zero based plane index. + // * @return U16 array of image plane data. + // */ + // protected int[] loadPlaneData(final int planeIndex) { + // ImageU16 plane = loadPlane(planeIndex); + // + // return (plane != null) ? plane.getData() : new int[0]; + // } /** diff --git a/src/main/java/azgracompress/benchmark/ScalarQuantizationBenchmark.java b/src/main/java/azgracompress/benchmark/ScalarQuantizationBenchmark.java index 6c0897a26ffe6a8b60a2ec49cff1bb617cade5a9..13f3b7aa5c405b8a0fd89d5bd72d950fe054d294 100644 --- a/src/main/java/azgracompress/benchmark/ScalarQuantizationBenchmark.java +++ b/src/main/java/azgracompress/benchmark/ScalarQuantizationBenchmark.java @@ -2,9 +2,9 @@ package azgracompress.benchmark; import azgracompress.U16; import azgracompress.cli.ParsedCliOptions; -import azgracompress.data.V3i; import azgracompress.de.DeException; import azgracompress.de.shade.ILShadeSolver; +import azgracompress.io.ConcretePlaneLoader; import azgracompress.quantization.QTrainIteration; import azgracompress.quantization.QuantizationValueCache; import azgracompress.quantization.scalar.LloydMaxU16ScalarQuantization; @@ -18,13 +18,6 @@ import java.io.OutputStreamWriter; public class ScalarQuantizationBenchmark extends BenchmarkBase { private boolean useDiffEvolution = false; - public ScalarQuantizationBenchmark(final String inputFile, - final String outputDirectory, - final int[] planes, - final V3i rawImageDims) { - super(inputFile, outputDirectory, planes, rawImageDims); - } - public ScalarQuantizationBenchmark(final ParsedCliOptions options) { super(options); } @@ -32,12 +25,22 @@ public class ScalarQuantizationBenchmark extends BenchmarkBase { @Override public void startBenchmark() { + ConcretePlaneLoader planeLoader = null; + try { + planeLoader = new ConcretePlaneLoader(options.getInputFileInfo()); + } catch (Exception e) { + e.printStackTrace(); + System.err.println("Unable to create SCIFIO reader."); + return; + } + if (planes.length < 1) { return; } boolean dirCreated = new File(this.outputDirectory).mkdirs(); System.out.println(String.format("|CODEBOOK| = %d", codebookSize)); ScalarQuantizer quantizer = null; + if (hasCacheFolder) { System.out.println("Loading codebook from cache"); QuantizationValueCache cache = new QuantizationValueCache(cacheFolder); @@ -51,11 +54,16 @@ public class ScalarQuantizationBenchmark extends BenchmarkBase { } System.out.println("Created quantizer from cache"); } else if (hasReferencePlane) { - final int[] refPlaneData = loadPlaneData(referencePlaneIndex); - if (refPlaneData.length == 0) { + final int[] refPlaneData; + + try { + refPlaneData = planeLoader.loadPlaneU16(referencePlaneIndex).getData(); + } catch (IOException e) { + e.printStackTrace(); System.err.println("Failed to load reference plane data."); return; } + if (useDiffEvolution) { quantizer = trainDifferentialEvolution(refPlaneData, codebookSize); } else { @@ -67,7 +75,14 @@ public class ScalarQuantizationBenchmark extends BenchmarkBase { for (final int planeIndex : planes) { System.out.println(String.format("Loading plane %d ...", planeIndex)); // NOTE(Moravec): Actual planeIndex is zero based. - final int[] planeData = loadPlaneData(planeIndex); + final int[] planeData; + try { + planeData = planeLoader.loadPlaneU16(planeIndex).getData(); + } catch (IOException e) { + e.printStackTrace(); + System.err.println("Failed to load plane data."); + return; + } if (planeData.length == 0) { System.err.println(String.format("Failed to load plane %d data. Skipping plane.", planeIndex)); return; diff --git a/src/main/java/azgracompress/benchmark/VectorQuantizationBenchmark.java b/src/main/java/azgracompress/benchmark/VectorQuantizationBenchmark.java index 16562b64f6f06c7ced5a4b3207b7a584a55d94ee..ebae87d18614acc4b3876f727139b376c2861f77 100644 --- a/src/main/java/azgracompress/benchmark/VectorQuantizationBenchmark.java +++ b/src/main/java/azgracompress/benchmark/VectorQuantizationBenchmark.java @@ -2,6 +2,7 @@ package azgracompress.benchmark; import azgracompress.cli.ParsedCliOptions; import azgracompress.data.*; +import azgracompress.io.ConcretePlaneLoader; import azgracompress.quantization.QuantizationValueCache; import azgracompress.quantization.vector.CodebookEntry; import azgracompress.quantization.vector.LBGResult; @@ -17,10 +18,6 @@ public class VectorQuantizationBenchmark extends BenchmarkBase { final static V2i DEFAULT_QVECTOR = new V2i(3, 3); - public VectorQuantizationBenchmark(String inputFile, String outputDirectory, int[] planes, V3i rawImageDims) { - super(inputFile, outputDirectory, planes, rawImageDims); - } - public VectorQuantizationBenchmark(final ParsedCliOptions options) { super(options); } @@ -51,6 +48,14 @@ public class VectorQuantizationBenchmark extends BenchmarkBase { if (planes.length < 1) { return; } + ConcretePlaneLoader planeLoader = null; + try { + planeLoader = new ConcretePlaneLoader(options.getInputFileInfo()); + } catch (Exception e) { + e.printStackTrace(); + System.err.println("Unable to create SCIFIO reader."); + return; + } if (qVector.getY() > 1) { System.out.println("2D qVector"); } else { @@ -77,9 +82,11 @@ public class VectorQuantizationBenchmark extends BenchmarkBase { } System.out.println("Created quantizer from cache"); } else if (hasReferencePlane) { - final ImageU16 plane = loadPlane(referencePlaneIndex); - - if (plane == null) { + final ImageU16 plane; + try { + plane = planeLoader.loadPlaneU16(referencePlaneIndex); + } catch (IOException e) { + e.printStackTrace(); System.err.println("Failed to load reference plane data."); return; } @@ -93,11 +100,12 @@ public class VectorQuantizationBenchmark extends BenchmarkBase { for (final int planeIndex : planes) { System.out.println(String.format("Loading plane %d ...", planeIndex)); - // NOTE(Moravec): Actual planeIndex is zero based. - - final ImageU16 plane = loadPlane(planeIndex - 1); - if (plane == null) { + final ImageU16 plane; + try { + plane = planeLoader.loadPlaneU16(planeIndex); + } catch (IOException e) { + e.printStackTrace(); System.err.println(String.format("Failed to load plane %d data. Skipping plane.", planeIndex)); return; } diff --git a/src/main/java/azgracompress/cli/InputFileInfo.java b/src/main/java/azgracompress/cli/InputFileInfo.java index 48597c6a258a4bac1d2b6065a4e6f38ce6c4c40e..b8a6f073bff769397fa234a23974069e698f1658 100644 --- a/src/main/java/azgracompress/cli/InputFileInfo.java +++ b/src/main/java/azgracompress/cli/InputFileInfo.java @@ -12,6 +12,8 @@ public class InputFileInfo { */ private final String filePath; + private boolean isRAW = true; + private V3i dimension; private boolean planeIndexSet = false; @@ -76,4 +78,12 @@ public class InputFileInfo { public V2i getPlaneRange() { return planeRange; } + + public boolean isRAW() { + return isRAW; + } + + public void setIsRaw(boolean RAW) { + isRAW = RAW; + } } diff --git a/src/main/java/azgracompress/cli/ParsedCliOptions.java b/src/main/java/azgracompress/cli/ParsedCliOptions.java index 549fea1d867beaaa24788ecd0640bc1e2ee49716..e1beddebec38f9ffb6e3c0b59945f236488d169d 100644 --- a/src/main/java/azgracompress/cli/ParsedCliOptions.java +++ b/src/main/java/azgracompress/cli/ParsedCliOptions.java @@ -130,7 +130,6 @@ public class ParsedCliOptions { return; } - inputFileInfo = new InputFileInfo(inputFileArguments[0]); // Decompress and Inspect methods doesn't require additional file information. @@ -159,7 +158,8 @@ public class ParsedCliOptions { // inputFileInfo is already created with TIFF type. // assert (inputFileInfo.getFileType() == FileType.TIFF) : "Not TIFF type in parse Tiff arguments."; - Reader reader = null; + inputFileInfo.setIsRaw(false); + Reader reader; try { reader = ScifioWrapper.getReader(inputFileInfo.getFilePath()); } catch (IOException | FormatException e) { @@ -223,6 +223,7 @@ public class ParsedCliOptions { return; } + inputFileInfo.setIsRaw(true); parseImageDims(inputFileArguments[1], errorBuilder); // User specified plane index or plane range. diff --git a/src/main/java/azgracompress/cli/functions/MeasurePlaneErrorFunction.java b/src/main/java/azgracompress/cli/functions/MeasurePlaneErrorFunction.java index 2fac49bdcd488f1d9ecf5fe300f50660e3709239..b44f108527e39889f04a44bc6ba2585e3a42a0e9 100644 --- a/src/main/java/azgracompress/cli/functions/MeasurePlaneErrorFunction.java +++ b/src/main/java/azgracompress/cli/functions/MeasurePlaneErrorFunction.java @@ -2,15 +2,6 @@ package azgracompress.cli.functions; import azgracompress.cli.CustomFunctionBase; import azgracompress.cli.ParsedCliOptions; -import azgracompress.data.ImageU16; -import azgracompress.data.V3i; -import azgracompress.io.RawDataIO; -import azgracompress.utilities.Utils; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.util.Arrays; public class MeasurePlaneErrorFunction extends CustomFunctionBase { public MeasurePlaneErrorFunction(ParsedCliOptions options) { @@ -66,53 +57,53 @@ public class MeasurePlaneErrorFunction extends CustomFunctionBase { } private boolean reportPlaneDifference(final String compressedFile, final String reportFile) { - final String referenceFile = "D:\\biology\\tiff_data\\benchmark\\fused_tp_10_ch_1_16bit.raw"; - - final V3i dims = new V3i(1041, 996, 946); - final int planePixelCount = dims.getX() * dims.getY(); - System.out.println(options.report()); - System.out.println("Run custom function."); - ImageU16 compressedPlane = null; - ImageU16 originalPlane = null; - ImageU16 differencePlane = null; - - PlaneError[] planeErrors = new PlaneError[dims.getZ()]; - - for (int planeIndex = 0; planeIndex < dims.getZ(); planeIndex++) { - try { - originalPlane = RawDataIO.loadImageU16(referenceFile, dims, planeIndex); - compressedPlane = RawDataIO.loadImageU16(compressedFile, dims, planeIndex); - } catch (IOException e) { - e.printStackTrace(); - return true; - } - final int[] diffData = Utils.getDifference(originalPlane.getData(), compressedPlane.getData()); - Utils.applyAbsFunction(diffData); - - - final double absDiffSum = Arrays.stream(diffData).mapToDouble(v -> v).sum(); - final double meanPixelError = absDiffSum / (double) planePixelCount; - - planeErrors[planeIndex] = new PlaneError(planeIndex, absDiffSum, meanPixelError); - // System.out.println("Finished plane: " + planeIndex); - } - - try (FileOutputStream fos = new FileOutputStream(reportFile, false); - OutputStreamWriter writer = new OutputStreamWriter(fos)) { - - writer.write("PlaneIndex\tErrorSum\tMeanError\n"); - - for (final PlaneError planeError : planeErrors) { - writer.write(String.format("%d\t%.4f\t%.4f\n", - planeError.getPlaneIndex(), - planeError.getAbsoluteError(), - planeError.getMeanAbsoluteError())); - } - - } catch (IOException e) { - e.printStackTrace(); - } - System.out.println("Finished reportPlaneDifference"); +// final String referenceFile = "D:\\biology\\tiff_data\\benchmark\\fused_tp_10_ch_1_16bit.raw"; +// +// final V3i dims = new V3i(1041, 996, 946); +// final int planePixelCount = dims.getX() * dims.getY(); +// System.out.println(options.report()); +// System.out.println("Run custom function."); +// ImageU16 compressedPlane = null; +// ImageU16 originalPlane = null; +// ImageU16 differencePlane = null; +// +// PlaneError[] planeErrors = new PlaneError[dims.getZ()]; +// +// for (int planeIndex = 0; planeIndex < dims.getZ(); planeIndex++) { +// try { +// originalPlane = RawDataIO.loadImageU16(referenceFile, dims, planeIndex); +// compressedPlane = RawDataIO.loadImageU16(compressedFile, dims, planeIndex); +// } catch (IOException e) { +// e.printStackTrace(); +// return true; +// } +// final int[] diffData = Utils.getDifference(originalPlane.getData(), compressedPlane.getData()); +// Utils.applyAbsFunction(diffData); +// +// +// final double absDiffSum = Arrays.stream(diffData).mapToDouble(v -> v).sum(); +// final double meanPixelError = absDiffSum / (double) planePixelCount; +// +// planeErrors[planeIndex] = new PlaneError(planeIndex, absDiffSum, meanPixelError); +// // System.out.println("Finished plane: " + planeIndex); +// } +// +// try (FileOutputStream fos = new FileOutputStream(reportFile, false); +// OutputStreamWriter writer = new OutputStreamWriter(fos)) { +// +// writer.write("PlaneIndex\tErrorSum\tMeanError\n"); +// +// for (final PlaneError planeError : planeErrors) { +// writer.write(String.format("%d\t%.4f\t%.4f\n", +// planeError.getPlaneIndex(), +// planeError.getAbsoluteError(), +// planeError.getMeanAbsoluteError())); +// } +// +// } catch (IOException e) { +// e.printStackTrace(); +// } +// System.out.println("Finished reportPlaneDifference"); return false; } } diff --git a/src/main/java/azgracompress/compression/SQImageCompressor.java b/src/main/java/azgracompress/compression/SQImageCompressor.java index 5a9e8684ed8a811bbde675f6404aa9663fbebea8..8dadac015b53275b0248598fc76714a2302a119e 100644 --- a/src/main/java/azgracompress/compression/SQImageCompressor.java +++ b/src/main/java/azgracompress/compression/SQImageCompressor.java @@ -5,8 +5,8 @@ import azgracompress.cli.InputFileInfo; import azgracompress.cli.ParsedCliOptions; import azgracompress.compression.exception.ImageCompressionException; import azgracompress.data.ImageU16; +import azgracompress.io.ConcretePlaneLoader; import azgracompress.io.OutBitStream; -import azgracompress.io.RawDataIO; import azgracompress.quantization.QuantizationValueCache; import azgracompress.quantization.scalar.LloydMaxU16ScalarQuantization; import azgracompress.quantization.scalar.ScalarQuantizer; @@ -85,6 +85,13 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm Stopwatch stopwatch = new Stopwatch(); final boolean hasGeneralQuantizer = options.hasCodebookCacheFolder() || options.hasReferencePlaneIndex(); + final ConcretePlaneLoader planeLoader; + try { + planeLoader = new ConcretePlaneLoader(inputFileInfo); + } catch (Exception e) { + throw new ImageCompressionException("Unable to create SCIFIO reader. " + e.getMessage()); + } + ScalarQuantizer quantizer = null; if (options.hasCodebookCacheFolder()) { Log("Loading codebook from cache file."); @@ -96,10 +103,8 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm stopwatch.restart(); ImageU16 referencePlane = null; try { - referencePlane = RawDataIO.loadImageU16(inputFileInfo.getFilePath(), - inputFileInfo.getDimensions(), - options.getReferencePlaneIndex()); - } catch (Exception ex) { + referencePlane = planeLoader.loadPlaneU16(options.getReferencePlaneIndex()); + } catch (IOException ex) { throw new ImageCompressionException("Unable to load reference plane data.", ex); } @@ -121,10 +126,8 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm ImageU16 plane = null; try { - plane = RawDataIO.loadImageU16(inputFileInfo.getFilePath(), - inputFileInfo.getDimensions(), - planeIndex); - } catch (Exception ex) { + plane = planeLoader.loadPlaneU16(planeIndex); + } catch (IOException ex) { throw new ImageCompressionException("Unable to load plane data.", ex); } @@ -152,13 +155,17 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm private int[] loadConfiguredPlanesData() throws ImageCompressionException { final InputFileInfo inputFileInfo = options.getInputFileInfo(); + final ConcretePlaneLoader planeLoader; + try { + planeLoader = new ConcretePlaneLoader(inputFileInfo); + } catch (Exception e) { + throw new ImageCompressionException("Unable to create SCIFIO reader. " + e.getMessage()); + } int[] trainData = null; if (inputFileInfo.isPlaneIndexSet()) { try { Log("Loading single plane data."); - trainData = RawDataIO.loadImageU16(inputFileInfo.getFilePath(), - inputFileInfo.getDimensions(), - inputFileInfo.getPlaneIndex()).getData(); + trainData = planeLoader.loadPlaneU16(inputFileInfo.getPlaneIndex()).getData(); } catch (IOException e) { throw new ImageCompressionException("Failed to load reference image data.", e); } @@ -166,7 +173,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm Log("Loading plane range data."); final int[] planes = getPlaneIndicesForCompression(); try { - trainData = RawDataIO.loadPlanesData(inputFileInfo.getFilePath(), inputFileInfo.getDimensions(), planes); + trainData = planeLoader.loadPlanesU16Data(planes); } catch (IOException e) { e.printStackTrace(); throw new ImageCompressionException("Failed to load plane range data.", e); @@ -174,7 +181,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm } else { Log("Loading all planes data."); try { - trainData = RawDataIO.loadAllPlanesData(inputFileInfo.getFilePath(), inputFileInfo.getDimensions()); + trainData = planeLoader.loadAllPlanesU16Data(); } catch (IOException e) { throw new ImageCompressionException("Failed to load all planes data.", e); } @@ -185,7 +192,6 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm @Override public void trainAndSaveCodebook() throws ImageCompressionException { - int[] trainData = loadConfiguredPlanesData(); LloydMaxU16ScalarQuantization lloydMax = new LloydMaxU16ScalarQuantization(trainData, diff --git a/src/main/java/azgracompress/compression/VQImageCompressor.java b/src/main/java/azgracompress/compression/VQImageCompressor.java index d4e62fed617853f85ba5605c6ad13e8dc77a9d46..b4c85a443db033aeacfa224541dd088e589b4738 100644 --- a/src/main/java/azgracompress/compression/VQImageCompressor.java +++ b/src/main/java/azgracompress/compression/VQImageCompressor.java @@ -5,8 +5,9 @@ import azgracompress.cli.ParsedCliOptions; import azgracompress.compression.exception.ImageCompressionException; import azgracompress.data.Chunk2D; import azgracompress.data.ImageU16; +import azgracompress.io.ConcretePlaneLoader; +import azgracompress.io.IPlaneLoader; import azgracompress.io.OutBitStream; -import azgracompress.io.RawDataIO; import azgracompress.quantization.QuantizationValueCache; import azgracompress.quantization.vector.CodebookEntry; import azgracompress.quantization.vector.LBGResult; @@ -90,6 +91,12 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm final InputFileInfo inputFileInfo = options.getInputFileInfo(); Stopwatch stopwatch = new Stopwatch(); final boolean hasGeneralQuantizer = options.hasCodebookCacheFolder() || options.hasReferencePlaneIndex(); + final ConcretePlaneLoader planeLoader; + try { + planeLoader = new ConcretePlaneLoader(inputFileInfo); + } catch (Exception e) { + throw new ImageCompressionException("Unable to create SCIFIO reader. " + e.getMessage()); + } VectorQuantizer quantizer = null; if (options.hasCodebookCacheFolder()) { @@ -102,10 +109,8 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm ImageU16 referencePlane = null; try { - referencePlane = RawDataIO.loadImageU16(inputFileInfo.getFilePath(), - inputFileInfo.getDimensions(), - options.getReferencePlaneIndex()); - } catch (Exception ex) { + referencePlane = planeLoader.loadPlaneU16(options.getReferencePlaneIndex()); + } catch (IOException ex) { throw new ImageCompressionException("Unable to load reference plane data.", ex); } @@ -125,10 +130,8 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm ImageU16 plane = null; try { - plane = RawDataIO.loadImageU16(inputFileInfo.getFilePath(), - inputFileInfo.getDimensions(), - planeIndex); - } catch (Exception ex) { + plane = planeLoader.loadPlaneU16(planeIndex); + } catch (IOException ex) { throw new ImageCompressionException("Unable to load plane data.", ex); } @@ -165,33 +168,38 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm * @return Quantization vectors of configured quantization. * @throws IOException When reading fails. */ - private int[][] loadPlaneQuantizationVectors(final int planeIndex) throws IOException { - ImageU16 refPlane = RawDataIO.loadImageU16(options.getInputFileInfo().getFilePath(), - options.getInputFileInfo().getDimensions(), - planeIndex); - + private int[][] loadPlaneQuantizationVectors(final IPlaneLoader planeLoader, + final int planeIndex) throws IOException { + ImageU16 refPlane = planeLoader.loadPlaneU16(planeIndex); return refPlane.toQuantizationVectors(options.getVectorDimension()); } private int[][] loadConfiguredPlanesData() throws ImageCompressionException { final int vectorSize = options.getVectorDimension().getX() * options.getVectorDimension().getY(); - final InputFileInfo ifi = options.getInputFileInfo(); + final InputFileInfo inputFileInfo = options.getInputFileInfo(); + final ConcretePlaneLoader planeLoader; + try { + planeLoader = new ConcretePlaneLoader(inputFileInfo); + } catch (Exception e) { + throw new ImageCompressionException("Unable to create SCIFIO reader. " + e.getMessage()); + } int[][] trainData = null; Stopwatch s = new Stopwatch(); s.start(); - if (ifi.isPlaneIndexSet()) { + if (inputFileInfo.isPlaneIndexSet()) { Log("VQ: Loading single plane data."); try { - trainData = loadPlaneQuantizationVectors(ifi.getPlaneIndex()); + + trainData = loadPlaneQuantizationVectors(planeLoader, inputFileInfo.getPlaneIndex()); } catch (IOException e) { throw new ImageCompressionException("Failed to load reference image data.", e); } } else { - Log(ifi.isPlaneRangeSet() ? "VQ: Loading plane range data." : "VQ: Loading all planes data."); + Log(inputFileInfo.isPlaneRangeSet() ? "VQ: Loading plane range data." : "VQ: Loading all planes data."); final int[] planeIndices = getPlaneIndicesForCompression(); final int chunkCountPerPlane = Chunk2D.calculateRequiredChunkCountPerPlane( - ifi.getDimensions().toV2i(), + inputFileInfo.getDimensions().toV2i(), options.getVectorDimension()); final int totalChunkCount = chunkCountPerPlane * planeIndices.length; @@ -201,7 +209,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm int planeCounter = 0; for (final int planeIndex : planeIndices) { try { - planeVectors = loadPlaneQuantizationVectors(planeIndex); + planeVectors = loadPlaneQuantizationVectors(planeLoader, planeIndex); assert (planeVectors.length == chunkCountPerPlane) : "Wrong chunk count per plane"; } catch (IOException e) { throw new ImageCompressionException(String.format("Failed to load plane %d image data.", diff --git a/src/main/java/azgracompress/data/ImageU16.java b/src/main/java/azgracompress/data/ImageU16.java index ddd7b4e1dd34ffeb8ad2df6e89130aa836ea53ca..8c5f7a53020ebcab62013f79f6e8e7e6608d9b5a 100644 --- a/src/main/java/azgracompress/data/ImageU16.java +++ b/src/main/java/azgracompress/data/ImageU16.java @@ -8,13 +8,17 @@ public class ImageU16 { private final int height; private int[] data; - public ImageU16(int width, int height, int[] data) { + public ImageU16(final int width, final int height, final int[] data) { assert ((width * height) == data.length) : "Wrong data size in ImageU16 constructor."; this.width = width; this.height = height; this.data = data; } + public ImageU16(final V2i dims, final int[] data) { + this(dims.getX(), dims.getY(), data); + } + private int index(final int x, final int y) { assert ((x >= 0 && x < height) && (y >= 0 && y < width)) : "Index out of bounds"; return (x * width) + y; diff --git a/src/main/java/azgracompress/io/ConcretePlaneLoader.java b/src/main/java/azgracompress/io/ConcretePlaneLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..12d7346a60c1ab3e4d0cbc6fe7e486bc002836dd --- /dev/null +++ b/src/main/java/azgracompress/io/ConcretePlaneLoader.java @@ -0,0 +1,45 @@ +package azgracompress.io; + +import azgracompress.cli.InputFileInfo; +import azgracompress.data.ImageU16; + +import java.io.IOException; + +public class ConcretePlaneLoader implements IPlaneLoader { + + private final IPlaneLoader loader; + + private final InputFileInfo inputFileInfo; + + /** + * Create plane loader. + * + * @param inputFileInfo Information about input file. + * @throws Exception When fails to create SCIFIO reader. + */ + public ConcretePlaneLoader(final InputFileInfo inputFileInfo) throws Exception { + this.inputFileInfo = inputFileInfo; + + if (inputFileInfo.isRAW()) { + loader = new RawDataLoader(inputFileInfo); + } else { + loader = new SCIFIOLoader(inputFileInfo); + } + } + + + @Override + public ImageU16 loadPlaneU16(int plane) throws IOException { + return loader.loadPlaneU16(plane); + } + + @Override + public int[] loadPlanesU16Data(int[] planes) throws IOException { + return loader.loadPlanesU16Data(planes); + } + + @Override + public int[] loadAllPlanesU16Data() throws IOException { + return loader.loadAllPlanesU16Data(); + } +} diff --git a/src/main/java/azgracompress/io/IPlaneLoader.java b/src/main/java/azgracompress/io/IPlaneLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..45026b5e04b3f62f24b9403b438e9e7ce9e056a9 --- /dev/null +++ b/src/main/java/azgracompress/io/IPlaneLoader.java @@ -0,0 +1,14 @@ +package azgracompress.io; + +import azgracompress.cli.InputFileInfo; +import azgracompress.data.ImageU16; + +import java.io.IOException; + +public interface IPlaneLoader { + ImageU16 loadPlaneU16(final int plane) throws IOException; + + int[] loadPlanesU16Data(int[] planes) throws IOException; + + int[] loadAllPlanesU16Data() throws IOException; +} diff --git a/src/main/java/azgracompress/io/ImagePlaneIO.java b/src/main/java/azgracompress/io/ImagePlaneIO.java deleted file mode 100644 index 69433036198bd857c3f2cf07ab1216376af85e5c..0000000000000000000000000000000000000000 --- a/src/main/java/azgracompress/io/ImagePlaneIO.java +++ /dev/null @@ -1,46 +0,0 @@ -package azgracompress.io; - -import azgracompress.data.ImageU16; -import azgracompress.data.V3i; -import io.scif.jj2000.j2k.NotImplementedError; - -import java.io.IOException; - -/** - * Class handling loading and writing of plane data. - * Multiple data types should be supported. - * For start: RAW, TIFF - */ -public class ImagePlaneIO { - - public static ImageU16 loadImageU16(final String rawFile, - final V3i rawDataDimension, - final int plane) throws IOException { - - // TODO(Moravec): Handle loading of different types. - // TODO(Moravec): If the loaded image is not U16 convert it to U16 image. - throw new NotImplementedError(); - } - - public static int[] loadPlanesData(final String rawFile, - final V3i rawDataDims, - int[] planes) throws IOException { - // TODO(Moravec): Handle loading of different types. - // TODO(Moravec): If the loaded image is not U16 convert it to U16 image. - throw new NotImplementedError(); - } - - public static int[] loadAllPlanesData(final String rawFile, final V3i imageDims) throws IOException { - // TODO(Moravec): Handle loading of different types. - // TODO(Moravec): If the loaded image is not U16 convert it to U16 image. - throw new NotImplementedError(); - } - - public static void writeImageU16(final String rawFile, - final ImageU16 image, - final boolean littleEndian) throws IOException { - - // TODO(Moravec): Handle writing of U16 image to multiple types. - throw new NotImplementedError(); - } -} diff --git a/src/main/java/azgracompress/io/RawDataIO.java b/src/main/java/azgracompress/io/RawDataIO.java index 5cf711f0271b8642282e2343d0eef24533218d9f..402df89490ae1281c60b4814598821c3f4684e18 100644 --- a/src/main/java/azgracompress/io/RawDataIO.java +++ b/src/main/java/azgracompress/io/RawDataIO.java @@ -1,119 +1,12 @@ package azgracompress.io; import azgracompress.data.ImageU16; -import azgracompress.data.V3i; import azgracompress.utilities.TypeConverter; -import java.io.*; -import java.util.Arrays; +import java.io.FileOutputStream; +import java.io.IOException; public class RawDataIO { - /** - * Load single U16 image from RAW data file. - * - * @param rawFile Path to the raw file. - * @param rawDataDimension X (Width), Y (Height) of plane and Z(Number of planes) - * @param plane Plane index. - * @return U16 image specified by the plane - */ - public static ImageU16 loadImageU16(final String rawFile, - final V3i rawDataDimension, - final int plane) throws IOException { - - byte[] buffer; - try (FileInputStream fileStream = new FileInputStream(rawFile)) { - final long planeSize = (long) rawDataDimension.getX() * (long) rawDataDimension.getY() * 2; - final long expectedFileSize = planeSize * rawDataDimension.getZ(); - final long fileSize = fileStream.getChannel().size(); - - - if (expectedFileSize != fileSize) { - throw new IOException( - "File specified by `rawFile` doesn't contains raw data for image of dimensions " + - "`rawDataDimension`"); - } - - final long planeOffset = plane * planeSize; - - buffer = new byte[(int) planeSize]; - if (fileStream.skip(planeOffset) != planeOffset) { - throw new IOException("Failed to skip."); - } - if (fileStream.read(buffer, 0, (int) planeSize) != planeSize) { - throw new IOException("Read wrong number of bytes."); - } - } - - return new ImageU16(rawDataDimension.getX(), - rawDataDimension.getY(), - TypeConverter.unsignedShortBytesToIntArray(buffer)); - } - - public static int[] loadPlanesData(final String rawFile, - final V3i rawDataDims, - int[] planes) throws IOException { - - if (planes.length < 1) - return new int[0]; - - final int planeValueCount = rawDataDims.getX() * rawDataDims.getY(); - final long planeDataSize = 2 * (long) planeValueCount; - - final long totalValueCount = (long) planeValueCount * planes.length; - int[] values = new int[(int) totalValueCount]; - - - if (totalValueCount > (long) Integer.MAX_VALUE) { - throw new IOException("Integer count is too big."); - } - - Arrays.sort(planes); - - try (FileInputStream fileStream = new FileInputStream(rawFile); - DataInputStream dis = new DataInputStream(new BufferedInputStream(fileStream, 8192))) { - - int lastIndex = 0; - int valIndex = 0; - - for (final int planeIndex : planes) { - // Skip specific number of bytes to get to the next plane. - final int requestedSkip = (planeIndex == 0) ? 0 : ((planeIndex - lastIndex) - 1) * (int) planeDataSize; - lastIndex = planeIndex; - - final int actualSkip = dis.skipBytes(requestedSkip); - if (requestedSkip != actualSkip) { - throw new IOException("Skip operation failed."); - } - - for (int i = 0; i < planeValueCount; i++) { - values[valIndex++] = dis.readUnsignedShort(); - } - - } - } - - return values; - } - - public static int[] loadAllPlanesData(final String rawFile, final V3i imageDims) throws IOException { - - final long dataSize = (long) imageDims.getX() * (long) imageDims.getY() * (long) imageDims.getZ(); - int[] values = new int[(int) dataSize]; - - if (dataSize > (long) Integer.MAX_VALUE) { - throw new IOException("RawFile size is too big."); - } - - try (FileInputStream fileStream = new FileInputStream(rawFile); - DataInputStream dis = new DataInputStream(new BufferedInputStream(fileStream, 8192))) { - - for (int i = 0; i < (int) dataSize; i++) { - values[i] = dis.readUnsignedShort(); - } - } - - return values; - } public static void writeImageU16(final String rawFile, final ImageU16 image, diff --git a/src/main/java/azgracompress/io/RawDataLoader.java b/src/main/java/azgracompress/io/RawDataLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..cb90165c80eb36ee88683ef7bcf4f32908a71088 --- /dev/null +++ b/src/main/java/azgracompress/io/RawDataLoader.java @@ -0,0 +1,115 @@ +package azgracompress.io; + +import azgracompress.cli.InputFileInfo; +import azgracompress.data.ImageU16; +import azgracompress.data.V3i; +import azgracompress.utilities.TypeConverter; + +import java.io.*; +import java.util.Arrays; + +public class RawDataLoader implements IPlaneLoader { + private final InputFileInfo inputFileInfo; + + public RawDataLoader(final InputFileInfo inputFileInfo) { + this.inputFileInfo = inputFileInfo; + } + + @Override + public ImageU16 loadPlaneU16(int plane) throws IOException { + byte[] buffer; + final V3i rawDataDimension = inputFileInfo.getDimensions(); + + try (FileInputStream fileStream = new FileInputStream(inputFileInfo.getFilePath())) { + final long planeSize = (long) rawDataDimension.getX() * (long) rawDataDimension.getY() * 2; + final long expectedFileSize = planeSize * rawDataDimension.getZ(); + final long fileSize = fileStream.getChannel().size(); + + + if (expectedFileSize != fileSize) { + throw new IOException( + "File specified by `rawFile` doesn't contains raw data for image of dimensions " + + "`rawDataDimension`"); + } + + final long planeOffset = plane * planeSize; + + buffer = new byte[(int) planeSize]; + if (fileStream.skip(planeOffset) != planeOffset) { + throw new IOException("Failed to skip."); + } + if (fileStream.read(buffer, 0, (int) planeSize) != planeSize) { + throw new IOException("Read wrong number of bytes."); + } + } + + return new ImageU16(rawDataDimension.getX(), + rawDataDimension.getY(), + TypeConverter.unsignedShortBytesToIntArray(buffer)); + } + + @Override + public int[] loadPlanesU16Data(int[] planes) throws IOException { + if (planes.length < 1) + return new int[0]; + + final int planeValueCount = inputFileInfo.getDimensions().getX() * inputFileInfo.getDimensions().getY(); + final long planeDataSize = 2 * (long) planeValueCount; + + final long totalValueCount = (long) planeValueCount * planes.length; + int[] values = new int[(int) totalValueCount]; + + + if (totalValueCount > (long) Integer.MAX_VALUE) { + throw new IOException("Integer count is too big."); + } + + Arrays.sort(planes); + + try (FileInputStream fileStream = new FileInputStream(inputFileInfo.getFilePath()); + DataInputStream dis = new DataInputStream(new BufferedInputStream(fileStream, 8192))) { + + int lastIndex = 0; + int valIndex = 0; + + for (final int planeIndex : planes) { + // Skip specific number of bytes to get to the next plane. + final int requestedSkip = (planeIndex == 0) ? 0 : ((planeIndex - lastIndex) - 1) * (int) planeDataSize; + lastIndex = planeIndex; + + final int actualSkip = dis.skipBytes(requestedSkip); + if (requestedSkip != actualSkip) { + throw new IOException("Skip operation failed."); + } + + for (int i = 0; i < planeValueCount; i++) { + values[valIndex++] = dis.readUnsignedShort(); + } + + } + } + + return values; + } + + @Override + public int[] loadAllPlanesU16Data() throws IOException { + final V3i imageDims = inputFileInfo.getDimensions(); + final long dataSize = (long) imageDims.getX() * (long) imageDims.getY() * (long) imageDims.getZ(); + int[] values = new int[(int) dataSize]; + + if (dataSize > (long) Integer.MAX_VALUE) { + throw new IOException("RawFile size is too big."); + } + + try (FileInputStream fileStream = new FileInputStream(inputFileInfo.getFilePath()); + DataInputStream dis = new DataInputStream(new BufferedInputStream(fileStream, 8192))) { + + for (int i = 0; i < (int) dataSize; i++) { + values[i] = dis.readUnsignedShort(); + } + } + + return values; + } +} diff --git a/src/main/java/azgracompress/io/SCIFIOLoader.java b/src/main/java/azgracompress/io/SCIFIOLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..3df37985ba100de81f599ab0cc7659f39592c116 --- /dev/null +++ b/src/main/java/azgracompress/io/SCIFIOLoader.java @@ -0,0 +1,51 @@ +package azgracompress.io; + +import azgracompress.ScifioWrapper; +import azgracompress.cli.InputFileInfo; +import azgracompress.data.ImageU16; +import azgracompress.utilities.TypeConverter; +import io.scif.FormatException; +import io.scif.Reader; +import io.scif.jj2000.j2k.NotImplementedError; + +import java.io.IOException; + +public class SCIFIOLoader implements IPlaneLoader { + + private final InputFileInfo inputFileInfo; + private final Reader reader; + + /** + * Create SCIFIO reader from input file. + * + * @param inputFileInfo Input file info. + * @throws IOException When fails to create SCIFIO reader. + * @throws FormatException When fails to create SCIFIO reader. + */ + public SCIFIOLoader(final InputFileInfo inputFileInfo) throws IOException, FormatException { + this.inputFileInfo = inputFileInfo; + this.reader = ScifioWrapper.getReader(this.inputFileInfo.getFilePath()); + } + + @Override + public ImageU16 loadPlaneU16(int plane) throws IOException { + byte[] planeBytes; + try { + planeBytes = reader.openPlane(0, plane).getBytes(); + } catch (FormatException e) { + throw new IOException("Unable to open plane with the reader. " + e.getMessage()); + } + final int[] data = TypeConverter.unsignedShortBytesToIntArray(planeBytes); + return new ImageU16(inputFileInfo.getDimensions().toV2i(), data); + } + + @Override + public int[] loadPlanesU16Data(int[] planes) throws IOException { + throw new NotImplementedError("NOT IMPLEMENTED"); + } + + @Override + public int[] loadAllPlanesU16Data() throws IOException { + throw new NotImplementedError("NOT IMPLEMENTED"); + } +}