From 2112a2f9389bf5d60620c70408cfb2e2464deed0 Mon Sep 17 00:00:00 2001 From: Vojtech Moravec <vojtech.moravec.st@vsb.cz> Date: Tue, 11 Aug 2020 08:32:02 +0200 Subject: [PATCH] Enable new loading in all places. This commit removes old methods from Chunk2D, which forced the change to the new IPlaneLoader API. We have also added new default functions which can load all three types of vectors from specified plane range. --- .../azgracompress/benchmark/VQBenchmark.java | 224 ++++++++---------- .../compression/VQImageCompressor.java | 141 +++-------- src/main/java/azgracompress/data/Chunk2D.java | 78 ------ .../java/azgracompress/data/ImageU16.java | 32 +-- .../azgracompress/io/loader/IPlaneLoader.java | 31 +++ .../io/loader/PlaneLoaderFactory.java | 2 +- .../java/azgracompress/utilities/Utils.java | 7 +- 7 files changed, 186 insertions(+), 329 deletions(-) diff --git a/src/main/java/azgracompress/benchmark/VQBenchmark.java b/src/main/java/azgracompress/benchmark/VQBenchmark.java index 3161f1a..366dfbf 100644 --- a/src/main/java/azgracompress/benchmark/VQBenchmark.java +++ b/src/main/java/azgracompress/benchmark/VQBenchmark.java @@ -1,36 +1,23 @@ package azgracompress.benchmark; -import azgracompress.U16; -import azgracompress.cache.QuantizationCacheManager; import azgracompress.cli.ParsedCliOptions; -import azgracompress.compression.CompressionOptions; -import azgracompress.data.*; -import azgracompress.io.loader.IPlaneLoader; -import azgracompress.io.loader.PlaneLoaderFactory; -import azgracompress.quantization.vector.LBGResult; -import azgracompress.quantization.vector.LBGVectorQuantizer; -import azgracompress.quantization.vector.VQCodebook; -import azgracompress.quantization.vector.VectorQuantizer; -import azgracompress.utilities.Utils; - -import java.io.File; -import java.io.IOException; +import azgracompress.data.Chunk2D; +import azgracompress.data.ImageU16; +import azgracompress.data.V2i; +import azgracompress.data.V3i; public class VQBenchmark extends BenchmarkBase { - final static V2i DEFAULT_QVECTOR = new V2i(3, 3); - public VQBenchmark(final ParsedCliOptions options) { super(options); } @Override public void startBenchmark() { - startBenchmark(DEFAULT_QVECTOR); + startBenchmark(options.getQuantizationVector()); } - private ImageU16 reconstructImageFromQuantizedVectors(final ImageU16 plane, - final int[][] vectors, + private ImageU16 reconstructImageFromQuantizedVectors(final int[][] vectors, final V2i qVector) { Chunk2D reconstructedChunk = new Chunk2D(new V2i(rawImageDims.getX(), rawImageDims.getY())); if (qVector.getY() > 1) { @@ -42,111 +29,98 @@ public class VQBenchmark extends BenchmarkBase { return reconstructedChunk.asImageU16(); } - private int[][] getPlaneVectors(final ImageU16 plane, final V2i qVector) { - return plane.toQuantizationVectors(qVector); - } - - public void startBenchmark(final V2i qVector) { - if (planes.length < 1) { - return; - } - IPlaneLoader planeLoader; - try { - planeLoader = PlaneLoaderFactory.getPlaneLoaderForInputFile(options.getInputDataInfo()); - } catch (Exception e) { - e.printStackTrace(); - System.err.println("Unable to create SCIFIO reader."); - return; - } - if (qVector.getY() > 1) { - System.out.println("2D qVector"); - } else { - System.out.println("1D qVector"); - } - boolean dirCreated = new File(this.outputDirectory).mkdirs(); - System.out.println(String.format("|CODEBOOK| = %d", codebookSize)); - VectorQuantizer quantizer = null; - - if (options.getCodebookType() == CompressionOptions.CodebookType.Global) { - System.out.println("Loading codebook from cache"); - QuantizationCacheManager cacheManager = new QuantizationCacheManager(cacheFolder); - final VQCodebook codebook = cacheManager.loadVQCodebook(inputFile, codebookSize, qVector.toV3i()); - if (codebook == null) { - System.err.println("Failed to read quantization vectors from cache."); - return; - } - quantizer = new VectorQuantizer(codebook); - System.out.println("Created quantizer from cache"); - - } else if (options.getCodebookType() == CompressionOptions.CodebookType.MiddlePlane) { - final int middlePlaneIndex = rawImageDims.getZ() / 2; - final ImageU16 middlePlane; - try { - - middlePlane = new ImageU16(options.getInputDataInfo().getDimensions().toV2i(), planeLoader.loadPlaneData(middlePlaneIndex)); - } catch (IOException e) { - e.printStackTrace(); - System.err.println("Failed to load middle plane data."); - return; - } - - final int[][] refPlaneData = getPlaneVectors(middlePlane, qVector); - LBGVectorQuantizer vqInitializer = new LBGVectorQuantizer(refPlaneData, - codebookSize, - workerCount, - qVector.toV3i()); - final LBGResult vqResult = vqInitializer.findOptimalCodebook(); - quantizer = new VectorQuantizer(vqResult.getCodebook()); - System.out.println("Created quantizer from middle plane."); - } - - for (final int planeIndex : planes) { - System.out.println(String.format("Loading plane %d ...", planeIndex)); - - final ImageU16 plane; - try { - plane = new ImageU16(options.getInputDataInfo().getDimensions().toV2i(), planeLoader.loadPlaneData(planeIndex)); - } catch (IOException e) { - e.printStackTrace(); - System.err.println(String.format("Failed to load plane %d data. Skipping plane.", planeIndex)); - return; - } - - final int[][] planeData = getPlaneVectors(plane, qVector); - - - if (options.getCodebookType() == CompressionOptions.CodebookType.Individual) { - LBGVectorQuantizer vqInitializer = new LBGVectorQuantizer(planeData, - codebookSize, - workerCount, - qVector.toV3i()); - LBGResult vqResult = vqInitializer.findOptimalCodebook(); - quantizer = new VectorQuantizer(vqResult.getCodebook()); - System.out.println("Created plane quantizer."); - } - - final String quantizedFile = String.format(QUANTIZED_FILE_TEMPLATE, planeIndex, codebookSize); - final String diffFile = String.format(DIFFERENCE_FILE_TEMPLATE, planeIndex, codebookSize); - final String absoluteDiffFile = String.format(ABSOLUTE_DIFFERENCE_FILE_TEMPLATE, - planeIndex, - codebookSize); - - final int[][] quantizedData = quantizer.quantize(planeData, workerCount); - - final ImageU16 quantizedImage = reconstructImageFromQuantizedVectors(plane, quantizedData, qVector); - - - final int[] diffArray = Utils.getDifference(plane.getData(), quantizedImage.getData()); - final double mse = Utils.calculateMse(diffArray); - final double PSNR = Utils.calculatePsnr(mse, U16.Max); - System.out.println(String.format("MSE: %.4f\tPSNR: %.4f(dB)", mse, PSNR)); - - if (!saveQuantizedPlaneData(quantizedImage.getData(), quantizedFile)) { - System.err.println("Failed to save quantized plane."); - return; - } - - saveDifference(diffArray, diffFile, absoluteDiffFile); - } + public void startBenchmark(final V3i qVector) { + // NOTE(Moravec): This will be enabled once we need to benchmark something. + // if (planes.length < 1) { + // return; + // } + // IPlaneLoader planeLoader; + // try { + // planeLoader = PlaneLoaderFactory.getPlaneLoaderForInputFile(options.getInputDataInfo()); + // } catch (Exception e) { + // e.printStackTrace(); + // System.err.println("Unable to create specific reader."); + // return; + // } + // if (qVector.getY() > 1) { + // System.out.println("2D qVector"); + // } else { + // System.out.println("1D qVector"); + // } + // boolean dirCreated = new File(this.outputDirectory).mkdirs(); + // System.out.printf("|CODEBOOK| = %d%n", codebookSize); + // VectorQuantizer quantizer = null; + // + // if (options.getCodebookType() == CompressionOptions.CodebookType.Global) { + // System.out.println("Loading codebook from cache"); + // QuantizationCacheManager cacheManager = new QuantizationCacheManager(cacheFolder); + // final VQCodebook codebook = cacheManager.loadVQCodebook(inputFile, codebookSize, qVector); + // if (codebook == null) { + // System.err.println("Failed to read quantization vectors from cache."); + // return; + // } + // quantizer = new VectorQuantizer(codebook); + // System.out.println("Created quantizer from cache"); + // + // } else if (options.getCodebookType() == CompressionOptions.CodebookType.MiddlePlane) { + // final int middlePlaneIndex = rawImageDims.getZ() / 2; + // int[][] refPlaneData; + // try { + // refPlaneData = planeLoader.loadVectorsFromPlaneRange(options, Utils.singlePlaneRange(middlePlaneIndex)); + // } catch (ImageCompressionException e) { + // e.printStackTrace(); + // System.err.println("Failed to load middle plane data."); + // return; + // } + // + // LBGVectorQuantizer vqInitializer = new LBGVectorQuantizer(refPlaneData, codebookSize, workerCount, qVector); + // final LBGResult vqResult = vqInitializer.findOptimalCodebook(); + // + // quantizer = new VectorQuantizer(vqResult.getCodebook()); + // System.out.println("Created quantizer from middle plane."); + // } + // + // for (final int planeIndex : planes) { + // System.out.printf("Loading plane %d ...%n", planeIndex); + // + // int[][] planeData; + // try { + // planeData = planeLoader.loadVectorsFromPlaneRange(options, Utils.singlePlaneRange(planeIndex)); + // } catch (ImageCompressionException e) { + // e.printStackTrace(); + // System.err.printf("Failed to load plane %d data.", planeIndex); + // return; + // } + // + // + // if (options.getCodebookType() == CompressionOptions.CodebookType.Individual) { + // LBGVectorQuantizer vqInitializer = new LBGVectorQuantizer(planeData, codebookSize, workerCount, qVector); + // LBGResult vqResult = vqInitializer.findOptimalCodebook(); + // quantizer = new VectorQuantizer(vqResult.getCodebook()); + // System.out.println("Created plane quantizer."); + // } + // + // final String quantizedFile = String.format(QUANTIZED_FILE_TEMPLATE, planeIndex, codebookSize); + // final String diffFile = String.format(DIFFERENCE_FILE_TEMPLATE, planeIndex, codebookSize); + // final String absoluteDiffFile = String.format(ABSOLUTE_DIFFERENCE_FILE_TEMPLATE, planeIndex, codebookSize); + // + // assert (quantizer != null); + // final int[][] quantizedData = quantizer.quantize(planeData, workerCount); + // + // final ImageU16 quantizedImage = reconstructImageFromQuantizedVectors(quantizedData, qVector.toV2i()); + // + // + // final int[] diffArray = Utils.getDifference(plane.getData(), quantizedImage.getData()); + // final double mse = Utils.calculateMse(diffArray); + // final double PSNR = Utils.calculatePsnr(mse, U16.Max); + // System.out.printf("MSE: %.4f\tPSNR: %.4f(dB)%n", mse, PSNR); + // + // if (!saveQuantizedPlaneData(quantizedImage.getData(), quantizedFile)) { + // System.err.println("Failed to save quantized plane."); + // return; + // } + // + // saveDifference(diffArray, diffFile, absoluteDiffFile); + // } } } diff --git a/src/main/java/azgracompress/compression/VQImageCompressor.java b/src/main/java/azgracompress/compression/VQImageCompressor.java index 976f40f..777236c 100644 --- a/src/main/java/azgracompress/compression/VQImageCompressor.java +++ b/src/main/java/azgracompress/compression/VQImageCompressor.java @@ -2,8 +2,6 @@ package azgracompress.compression; import azgracompress.cache.QuantizationCacheManager; import azgracompress.compression.exception.ImageCompressionException; -import azgracompress.data.Chunk2D; -import azgracompress.data.ImageU16; import azgracompress.data.Range; import azgracompress.fileformat.QuantizationType; import azgracompress.huffman.Huffman; @@ -12,6 +10,7 @@ import azgracompress.io.loader.IPlaneLoader; import azgracompress.io.loader.PlaneLoaderFactory; import azgracompress.quantization.vector.*; import azgracompress.utilities.Stopwatch; +import azgracompress.utilities.Utils; import org.jetbrains.annotations.NotNull; import java.io.DataOutputStream; @@ -32,9 +31,9 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm private VectorQuantizer trainVectorQuantizerFromPlaneVectors(final int[][] planeVectors) { LBGVectorQuantizer vqInitializer = new LBGVectorQuantizer(planeVectors, - getCodebookSize(), - options.getWorkerCount(), - options.getQuantizationVector()); + getCodebookSize(), + options.getWorkerCount(), + options.getQuantizationVector()); LBGResult vqResult = vqInitializer.findOptimalCodebook(); return new VectorQuantizer(vqResult.getCodebook()); } @@ -79,14 +78,14 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm QuantizationCacheManager cacheManager = new QuantizationCacheManager(options.getCodebookCacheFolder()); if (!cacheManager.doesVQCacheExists(options.getInputDataInfo().getCacheFileName(), - getCodebookSize(), - options.getQuantizationVector())) { + getCodebookSize(), + options.getQuantizationVector())) { trainAndSaveCodebook(); } final VQCodebook codebook = cacheManager.loadVQCodebook(options.getInputDataInfo().getCacheFileName(), - getCodebookSize(), - options.getQuantizationVector()); + getCodebookSize(), + options.getQuantizationVector()); if (codebook == null) { throw new ImageCompressionException("Failed to read quantization vectors from cache."); @@ -132,17 +131,8 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm writeQuantizerToCompressStream(quantizer, compressStream); } else if (options.getCodebookType() == CompressionOptions.CodebookType.MiddlePlane) { stopwatch.restart(); - - final int middlePlaneIndex = getMiddlePlaneIndex(); - ImageU16 middlePlane = null; - try { - middlePlane = new ImageU16(options.getInputDataInfo().getDimensions().toV2i(), planeLoader.loadPlaneData(middlePlaneIndex)); - } catch (IOException ex) { - throw new ImageCompressionException("Unable to load reference plane data.", ex); - } - - reportStatusToListeners(String.format("Training vector quantizer from middle plane %d.", middlePlaneIndex)); - final int[][] refPlaneVectors = middlePlane.toQuantizationVectors(options.getQuantizationVector().toV2i()); + reportStatusToListeners("Training vector quantizer from middle plane."); + final int[][] refPlaneVectors = planeLoader.loadVectorsFromPlaneRange(options, Utils.singlePlaneRange(getMiddlePlaneIndex())); quantizer = trainVectorQuantizerFromPlaneVectors(refPlaneVectors); huffman = createHuffmanCoder(huffmanSymbols, quantizer.getFrequencies()); writeQuantizerToCompressStream(quantizer, compressStream); @@ -158,14 +148,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm stopwatch.restart(); reportStatusToListeners(String.format("Loading plane %d.", planeIndex)); - ImageU16 plane = null; - try { - plane = new ImageU16(options.getInputDataInfo().getDimensions().toV2i(), planeLoader.loadPlaneData(planeIndex)); - } catch (IOException ex) { - throw new ImageCompressionException("Unable to load plane data.", ex); - } - - final int[][] planeVectors = plane.toQuantizationVectors(options.getQuantizationVector().toV2i()); + final int[][] planeVectors = planeLoader.loadVectorsFromPlaneRange(options, Utils.singlePlaneRange(planeIndex)); if (!hasGeneralQuantizer) { reportStatusToListeners(String.format("Training vector quantizer from plane %d.", planeIndex)); @@ -182,99 +165,41 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm stopwatch.stop(); reportProgressToListeners(planeIndex, planeIndices.length, - "Finished compression of plane %d in %s.", planeIndex, stopwatch.getElapsedTimeString()); + "Finished compression of plane %d in %s.", planeIndex, stopwatch.getElapsedTimeString()); } return planeDataSizes; } - - /** - * Load plane and convert the plane into quantization vectors. - * - * @param planeIndex Zero based plane index. - * @return Quantization vectors of configured quantization. - * @throws IOException When reading fails. - */ - - private int[][] loadPlaneQuantizationVectors(final IPlaneLoader planeLoader, - final int planeIndex) throws IOException { - ImageU16 refPlane = new ImageU16(options.getInputDataInfo().getDimensions().toV2i(), planeLoader.loadPlaneData(planeIndex)); - return refPlane.toQuantizationVectors(options.getQuantizationVector().toV2i()); - } - - private int[][] loadConfiguredPlanesData() throws ImageCompressionException { + @Override + public void trainAndSaveCodebook() throws ImageCompressionException { + reportStatusToListeners("Loading image data..."); final IPlaneLoader planeLoader; try { planeLoader = PlaneLoaderFactory.getPlaneLoaderForInputFile(options.getInputDataInfo()); - planeLoader.setWorkerCount(options.getWorkerCount()); } catch (Exception e) { - throw new ImageCompressionException("Unable to create reader. " + e.getMessage()); + throw new ImageCompressionException("Unable to create plane reader. " + e.getMessage()); } - if (options.getQuantizationType().isOneOf(QuantizationType.Vector1D, QuantizationType.Vector2D)) { - // TODO: Chunk2D operations should eventually be moved to loaders. - // Same as voxel loading, so that we wouldn't have to copy data twice. - final int vectorSize = options.getQuantizationVector().toV2i().multiplyTogether(); - - int[][] trainData; - Stopwatch s = Stopwatch.startNew(); - if (options.getInputDataInfo().isPlaneIndexSet()) { - reportStatusToListeners("VQ: Loading single plane data."); - try { - trainData = loadPlaneQuantizationVectors(planeLoader, options.getInputDataInfo().getPlaneIndex()); - } catch (IOException e) { - throw new ImageCompressionException("Failed to load plane data.", e); - } - } else { - reportStatusToListeners(options.getInputDataInfo().isPlaneRangeSet() ? - "VQ: Loading plane range data." : "VQ: Loading all planes data."); - - final int[] planeIndices = getPlaneIndicesForCompression(); - final int chunkCountPerPlane = Chunk2D.calculateRequiredChunkCount(options.getInputDataInfo().getDimensions().toV2i(), - options.getQuantizationVector().toV2i()); - final int totalChunkCount = chunkCountPerPlane * planeIndices.length; - trainData = new int[totalChunkCount][vectorSize]; - - int[][] planeVectors; - int planeCounter = 0; - for (final int planeIndex : planeIndices) { - try { - 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.", planeIndex), e); - } - - System.arraycopy(planeVectors, 0, trainData, (planeCounter * chunkCountPerPlane), chunkCountPerPlane); - ++planeCounter; - } - } - s.stop(); - reportStatusToListeners("Quantization vector load took: " + s.getElapsedTimeString()); - return trainData; - } else { - if (options.getQuantizationType() != QuantizationType.Vector3D) { - throw new ImageCompressionException("Invalid QuantizationType, expected: `QuantizationType.Vector3D`, but got: " + - options.getQuantizationType().toString()); - } - try { - return planeLoader.loadVoxels(options.getQuantizationVector()); - } catch (IOException e) { - throw new ImageCompressionException("Unable to load voxels.", e); - } + int[][] trainingData; + if (options.getInputDataInfo().isPlaneIndexSet()) { + reportStatusToListeners("VQ: Loading single plane data."); + final int planeIndex = options.getInputDataInfo().getPlaneIndex(); + trainingData = planeLoader.loadVectorsFromPlaneRange(options, new Range<>(planeIndex, planeIndex + 1)); + } else if (options.getInputDataInfo().isPlaneRangeSet()) { + reportStatusToListeners("VQ: Loading plane range data."); + trainingData = planeLoader.loadVectorsFromPlaneRange(options, options.getInputDataInfo().getPlaneRange()); + } else { + reportStatusToListeners("VQ: Loading all planes data."); + trainingData = planeLoader.loadVectorsFromPlaneRange(options, + new Range<>(0, options.getInputDataInfo().getDimensions().getZ())); } - } - @Override - public void trainAndSaveCodebook() throws ImageCompressionException { - reportStatusToListeners("Loading image data..."); - final int[][] trainingData = loadConfiguredPlanesData(); LBGVectorQuantizer vqInitializer = new LBGVectorQuantizer(trainingData, - getCodebookSize(), - options.getWorkerCount(), - options.getQuantizationVector()); + getCodebookSize(), + options.getWorkerCount(), + options.getQuantizationVector()); reportStatusToListeners("Starting LBG optimization."); vqInitializer.setStatusListener(this::reportStatusToListeners); @@ -348,8 +273,8 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm voxelLayersSizes[voxelLayerIndex] = writeHuffmanEncodedIndices(compressStream, huffman, indices); stopwatch.stop(); reportProgressToListeners(voxelLayerIndex, voxelLayerCount, - "%d/%d Finished voxel layer %s compression pass in %s", - voxelLayerIndex, voxelLayerCount, voxelLayerRange.toString(), stopwatch.getElapsedTimeString()); + "%d/%d Finished voxel layer %s compression pass in %s", + voxelLayerIndex, voxelLayerCount, voxelLayerRange.toString(), stopwatch.getElapsedTimeString()); } return voxelLayersSizes; diff --git a/src/main/java/azgracompress/data/Chunk2D.java b/src/main/java/azgracompress/data/Chunk2D.java index 1f337de..3e4664d 100644 --- a/src/main/java/azgracompress/data/Chunk2D.java +++ b/src/main/java/azgracompress/data/Chunk2D.java @@ -70,32 +70,6 @@ public class Chunk2D { return String.format("2D shape %s %d values", dims.toString(), data.length); } - /** - * Divide this Chunk to 1D row vector of given length. - * - * @param vectorSize Vector length. - * @return Array of row vectors. - */ - public int[][] divideInto1DVectors(final int vectorSize) { - final int rowVectorCount = (int) Math.ceil(dims.getX() / (float) vectorSize); - final int vectorCount = rowVectorCount * dims.getY(); - int[][] imageVectors = new int[vectorCount][vectorSize]; - - int vec = 0; - int srcX; - for (int row = 0; row < dims.getY(); row++) { - for (int vecIndex = 0; vecIndex < rowVectorCount; vecIndex++) { - for (int x = 0; x < vectorSize; x++) { - srcX = (vecIndex * vectorSize) + x; - imageVectors[vec][x] = isInside(srcX, row) ? data[index(srcX, row)] : FILL_VALUE; - } - ++vec; - } - } - - return imageVectors; - } - /** * Reconstruct this Chunk from array of 1D row vectors. * @@ -125,27 +99,6 @@ public class Chunk2D { } } - /** - * Divide this Chunk to 2D matrices of given dimensions. - * - * @param qVectorDims Matrix dimension. - * @return Array of matrix data. - */ - public int[][] divideInto2DVectors(final V2i qVectorDims) { - final int chunkSize = qVectorDims.getX() * qVectorDims.getY(); - final int chunkCount = calculateRequiredChunkCount(qVectorDims); - - int[][] vectors = new int[chunkCount][chunkSize]; - int vecIndex = 0; - - for (int chunkYOffset = 0; chunkYOffset < dims.getY(); chunkYOffset += qVectorDims.getY()) { - for (int chunkXOffset = 0; chunkXOffset < dims.getX(); chunkXOffset += qVectorDims.getX()) { - copyDataToVector(vectors[vecIndex++], qVectorDims, chunkXOffset, chunkYOffset); - } - } - return vectors; - } - /** * Reconstruct this Chunk (copy data) from matrix vectors. * @@ -169,17 +122,6 @@ public class Chunk2D { assert (vecIndex == vectors.length); } - - /** - * Calculate the number of required 2D matrices for plane. - * - * @param chunkDims Matrix dimension. - * @return Number of required chunks. - */ - private int calculateRequiredChunkCount(final V2i chunkDims) { - return calculateRequiredChunkCount(dims, chunkDims); - } - /** * Calculate the number of required 2D matrices for plane of given dimensions. * @@ -205,26 +147,6 @@ public class Chunk2D { return (((x >= 0) && (x < dims.getX())) && (y >= 0) && (y < dims.getY())); } - /** - * Copy this chunk data to chunk vector. - * - * @param vector Chunk vector. - * @param qVectorDims Dimensions of the vector. - * @param chunkXOffset Chunk X offset - * @param chunkYOffset Chunk Y offset. - */ - private void copyDataToVector(int[] vector, final V2i qVectorDims, final int chunkXOffset, final int chunkYOffset) { - int srcX, srcY; - for (int y = 0; y < qVectorDims.getY(); y++) { - srcY = chunkYOffset + y; - for (int x = 0; x < qVectorDims.getX(); x++) { - srcX = chunkXOffset + x; - final int dstIndex = index(x, y, qVectorDims.getY()); - vector[dstIndex] = isInside(srcX, srcY) ? data[index(srcX, srcY)] : FILL_VALUE; - } - } - } - /** * Copy data from chunk vector to this chunk. * diff --git a/src/main/java/azgracompress/data/ImageU16.java b/src/main/java/azgracompress/data/ImageU16.java index 65e9afb..589ee1e 100644 --- a/src/main/java/azgracompress/data/ImageU16.java +++ b/src/main/java/azgracompress/data/ImageU16.java @@ -54,20 +54,20 @@ public class ImageU16 { return height; } - /** - * Chunk the image data into quantization vectors of requested dimension. - * - * @param qVectorDims Quantization vector dimension. - * @return Array of quantization vectors. - */ - public int[][] toQuantizationVectors(final V2i qVectorDims) { - if (qVectorDims.getY() == 1) { - // 1D row vectors. - return as2dChunk().divideInto1DVectors(qVectorDims.getX()); - } else { - // 2D matrix vectors. - return as2dChunk().divideInto2DVectors(qVectorDims); - //return Chunk2D.chunksAsImageVectors(as2dChunk().divideIntoChunks(qVectorDims)); - } - } +// /** +// * Chunk the image data into quantization vectors of requested dimension. +// * +// * @param qVectorDims Quantization vector dimension. +// * @return Array of quantization vectors. +// */ +// public int[][] toQuantizationVectors(final V2i qVectorDims) { +// if (qVectorDims.getY() == 1) { +// // 1D row vectors. +// return as2dChunk().divideInto1DVectors(qVectorDims.getX()); +// } else { +// // 2D matrix vectors. +// return as2dChunk().divideInto2DVectors(qVectorDims); +// //return Chunk2D.chunksAsImageVectors(as2dChunk().divideIntoChunks(qVectorDims)); +// } +// } } diff --git a/src/main/java/azgracompress/io/loader/IPlaneLoader.java b/src/main/java/azgracompress/io/loader/IPlaneLoader.java index db338cf..e88a469 100644 --- a/src/main/java/azgracompress/io/loader/IPlaneLoader.java +++ b/src/main/java/azgracompress/io/loader/IPlaneLoader.java @@ -1,5 +1,7 @@ package azgracompress.io.loader; +import azgracompress.compression.CompressionOptions; +import azgracompress.compression.exception.ImageCompressionException; import azgracompress.data.Range; import azgracompress.data.V2i; import azgracompress.data.V3i; @@ -124,4 +126,33 @@ public interface IPlaneLoader { * @param threadCount Available thread count for loader. */ void setWorkerCount(final int threadCount); + + /** + * Load correct type of vectors (quantization type in options) from specified plane range. + * + * @param planeRange Plane range to load vectors from. + * @return Vector data from plane range. + * @throws ImageCompressionException When fails to load plane range. + */ + default int[][] loadVectorsFromPlaneRange(final CompressionOptions options, + final Range<Integer> planeRange) throws ImageCompressionException { + + setWorkerCount(supportParallelLoading() ? options.getWorkerCount() : 1); + + try { + switch (options.getQuantizationType()) { + case Vector1D: + return loadRowVectors(options.getQuantizationVector().getX(), planeRange); + case Vector2D: + return loadBlocks(options.getQuantizationVector().toV2i(), planeRange); + case Vector3D: + return loadVoxels(options.getQuantizationVector(), planeRange); + default: { + throw new ImageCompressionException("Invalid QuantizationType '" + options.getQuantizationType().toString() + "'"); + } + } + } catch (IOException e) { + throw new ImageCompressionException("Unable to load vectors QuantizationType=" + options.getQuantizationType(), e); + } + } } diff --git a/src/main/java/azgracompress/io/loader/PlaneLoaderFactory.java b/src/main/java/azgracompress/io/loader/PlaneLoaderFactory.java index b147eba..6783ba6 100644 --- a/src/main/java/azgracompress/io/loader/PlaneLoaderFactory.java +++ b/src/main/java/azgracompress/io/loader/PlaneLoaderFactory.java @@ -18,7 +18,7 @@ public final class PlaneLoaderFactory { case RawDataLoader: return new RawDataLoader((FileInputData) inputDataInfo); case SCIFIOLoader: - return new SCIFIOLoader((FileInputData)inputDataInfo); + return new SCIFIOLoader((FileInputData) inputDataInfo); case ImageJBufferLoader: return new ImageJBufferLoader((BufferInputData) inputDataInfo); default: diff --git a/src/main/java/azgracompress/utilities/Utils.java b/src/main/java/azgracompress/utilities/Utils.java index 9d7a773..008f650 100644 --- a/src/main/java/azgracompress/utilities/Utils.java +++ b/src/main/java/azgracompress/utilities/Utils.java @@ -1,6 +1,7 @@ package azgracompress.utilities; import azgracompress.U16; +import azgracompress.data.Range; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -10,6 +11,10 @@ import java.util.ArrayList; public class Utils { + public static Range<Integer> singlePlaneRange(final int index) { + return new Range<>(index, index + 1); + } + public static double calculatePsnr(final double mse, final int signalMax) { double psnr = 10.0 * Math.log10((Math.pow(signalMax, 2) / mse)); return psnr; @@ -19,7 +24,7 @@ public class Utils { FileInputStream fileStream = new FileInputStream(path); try { throw new FileNotFoundException("Implement this actually!"); -// return fileStream.readAllBytes(); + // return fileStream.readAllBytes(); } catch (IOException e) { e.printStackTrace(); } -- GitLab