From 882bbd231ba8a9ce5cfbd1ffb77d33aa5868b46d Mon Sep 17 00:00:00 2001 From: Vojtech Moravec <vojtech.moravec.st@vsb.cz> Date: Wed, 2 Dec 2020 14:03:47 +0100 Subject: [PATCH] Use the improved codebook API. --- .../qcmp/cli/functions/DebugFunction.java | 75 ++++++++----------- .../CompressorDecompressorBase.java | 16 +--- .../qcmp/compression/SQImageCompressor.java | 14 ++-- .../qcmp/compression/SQImageDecompressor.java | 29 ++++--- .../qcmp/compression/VQImageCompressor.java | 18 ++--- .../qcmp/compression/VQImageDecompressor.java | 21 +++--- .../scalar/LloydMaxU16ScalarQuantization.java | 5 +- .../qcmp/quantization/vector/LBGResult.java | 5 +- .../vector/LBGVectorQuantizer.java | 16 ++-- .../qcmp/quantization/vector/VQCodebook.java | 1 + .../quantization/vector/VectorQuantizer.java | 13 ++-- 11 files changed, 92 insertions(+), 121 deletions(-) diff --git a/src/main/java/cz/it4i/qcmp/cli/functions/DebugFunction.java b/src/main/java/cz/it4i/qcmp/cli/functions/DebugFunction.java index 32b6205..e2b59ee 100644 --- a/src/main/java/cz/it4i/qcmp/cli/functions/DebugFunction.java +++ b/src/main/java/cz/it4i/qcmp/cli/functions/DebugFunction.java @@ -1,19 +1,7 @@ package cz.it4i.qcmp.cli.functions; -import cz.it4i.qcmp.cache.QuantizationCacheManager; -import cz.it4i.qcmp.cache.VqQvcFile; import cz.it4i.qcmp.cli.CompressionOptionsCLIParser; import cz.it4i.qcmp.cli.CustomFunctionBase; -import cz.it4i.qcmp.huffman.HuffmanNode; -import cz.it4i.qcmp.huffman.HuffmanTreeBuilder; -import cz.it4i.qcmp.io.InBitStream; -import cz.it4i.qcmp.io.OutBitStream; -import cz.it4i.qcmp.quantization.vector.VQCodebook; -import cz.it4i.qcmp.utilities.Utils; - -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; @SuppressWarnings("ConstantConditions") public class DebugFunction extends CustomFunctionBase { @@ -29,38 +17,37 @@ public class DebugFunction extends CustomFunctionBase { @Override public boolean run() { - final VQCodebook codebook = ((VqQvcFile) QuantizationCacheManager.readCacheFile("D:\\tmp\\codebook.qvc")).getCodebook(); - - final int[] symbols = new int[codebook.getCodebookSize()]; - for (int i = 0; i < codebook.getCodebookSize(); i++) { - symbols[i] = i; - } - - final HuffmanTreeBuilder huffmanBuilder = new HuffmanTreeBuilder(symbols, codebook.getVectorFrequencies()); - huffmanBuilder.buildHuffmanTree(); - - final int bitsPerSymbol = (int) Utils.log2(codebook.getCodebookSize()); - try (final OutBitStream bitStream = new OutBitStream(new FileOutputStream("D:\\tmp\\huffman_tree.data", false), - bitsPerSymbol, - 64)) { - huffmanBuilder.createEncoder().getRoot().writeToBinaryStream(bitStream); - } catch (final IOException e) { - e.printStackTrace(); - } - - - HuffmanNode readRoot = null; - try (final InBitStream inBitStream = new InBitStream(new FileInputStream("D:\\tmp\\huffman_tree.data"), bitsPerSymbol, 256)) { - readRoot = HuffmanNode.readFromStream(inBitStream); - } catch (final IOException ex) { - ex.printStackTrace(); - } - - readRoot. - - final boolean equal = huffmanBuilder.createEncoder().getRoot().treeEqual(readRoot); - - System.out.println(readRoot != null); + // final VQCodebook codebook = ((VqQvcFile) QuantizationCacheManager.readCacheFile("D:\\tmp\\codebook.qvc")).getCodebook(); + // + // final int[] symbols = new int[codebook.getCodebookSize()]; + // for (int i = 0; i < codebook.getCodebookSize(); i++) { + // symbols[i] = i; + // } + // + // final HuffmanTreeBuilder huffmanBuilder = new HuffmanTreeBuilder(symbols, codebook.getVectorFrequencies()); + // huffmanBuilder.buildHuffmanTree(); + // + // final int bitsPerSymbol = (int) Utils.log2(codebook.getCodebookSize()); + // try (final OutBitStream bitStream = new OutBitStream(new FileOutputStream("D:\\tmp\\huffman_tree.data", false), + // bitsPerSymbol, + // 64)) { + // huffmanBuilder.createEncoder().getRoot().writeToBinaryStream(bitStream); + // } catch (final IOException e) { + // e.printStackTrace(); + // } + // + // + // HuffmanNode readRoot = null; + // try (final InBitStream inBitStream = new InBitStream(new FileInputStream("D:\\tmp\\huffman_tree.data"), bitsPerSymbol, + // 256)) { + // readRoot = HuffmanNode.readFromStream(inBitStream); + // } catch (final IOException ex) { + // ex.printStackTrace(); + // } + // + // final boolean equal = huffmanBuilder.createEncoder().getRoot().treeEqual(readRoot); + // + // System.out.println(readRoot != null); return true; } diff --git a/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java b/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java index f41106e..0278a0e 100644 --- a/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java +++ b/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java @@ -3,9 +3,7 @@ package cz.it4i.qcmp.compression; import cz.it4i.qcmp.compression.exception.ImageCompressionException; import cz.it4i.qcmp.compression.listeners.IProgressListener; import cz.it4i.qcmp.compression.listeners.IStatusListener; -import cz.it4i.qcmp.huffman.HuffmanDecoder; import cz.it4i.qcmp.huffman.HuffmanEncoder; -import cz.it4i.qcmp.huffman.HuffmanTreeBuilder; import cz.it4i.qcmp.io.InputData; import cz.it4i.qcmp.io.OutBitStream; @@ -101,19 +99,7 @@ public abstract class CompressorDecompressorBase { } return symbols; } - - protected HuffmanEncoder createHuffmanEncoder(final int[] symbols, final long[] frequencies) { - final HuffmanTreeBuilder huffman = new HuffmanTreeBuilder(symbols, frequencies); - huffman.buildHuffmanTree(); - return huffman.createEncoder(); - } - - protected HuffmanDecoder createHuffmanDecoder(final int[] symbols, final long[] frequencies) { - final HuffmanTreeBuilder huffman = new HuffmanTreeBuilder(symbols, frequencies); - huffman.buildHuffmanTree(); - return huffman.createDecoder(); - } - + protected int[] getPlaneIndicesForCompression(final InputData inputData) { if (inputData.isPlaneIndexSet()) { return new int[]{inputData.getPlaneIndex()}; diff --git a/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java b/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java index b782dcc..effc516 100644 --- a/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java +++ b/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java @@ -45,8 +45,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm public void preloadGlobalCodebook(final IQvcFile codebookCacheFile) { final SQCodebook cachedCodebook = ((SqQvcFile) codebookCacheFile).getCodebook(); cachedQuantizer = new ScalarQuantizer(cachedCodebook); - cachedHuffmanEncoder = createHuffmanEncoder(createHuffmanSymbols(cachedCodebook.getCodebookSize()), - cachedCodebook.getSymbolFrequencies()); + cachedHuffmanEncoder = cachedCodebook.getHuffmanEncoder(); } /** @@ -89,8 +88,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm trainAndSaveCodebook(); } - final SQCodebook codebook = cacheManager.loadSQCodebook(options.getInputDataInfo().getCacheFileName(), - getCodebookSize()); + final SQCodebook codebook = cacheManager.loadSQCodebook(options.getInputDataInfo().getCacheFileName(), getCodebookSize()); if (codebook == null) { throw new ImageCompressionException("Failed to read quantization values from cache file."); } @@ -123,7 +121,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm reportStatusToListeners("Loading codebook from cache file."); quantizer = loadQuantizerFromCache(); - huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getCodebook().getSymbolFrequencies()); + huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder(); reportStatusToListeners("Cached quantizer with huffman coder created."); writeCodebookToOutputStream(quantizer, compressStream); @@ -139,7 +137,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm reportStatusToListeners(String.format("Training scalar quantizer from middle plane %d.", middlePlaneIndex)); quantizer = trainScalarQuantizerFromData(middlePlaneData); - huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getCodebook().getSymbolFrequencies()); + huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder(); stopwatch.stop(); writeCodebookToOutputStream(quantizer, compressStream); @@ -175,7 +173,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm quantizer = trainScalarQuantizerFromData(planeData); writeCodebookToOutputStream(quantizer, compressStream); - huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getCodebook().getSymbolFrequencies()); + huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder(); } assert (quantizer != null) : "Scalar Quantizer wasn't initialized."; @@ -200,7 +198,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm } catch (final Exception e) { throw new ImageCompressionException("Unable to create SCIFIO reader. " + e.getMessage()); } - int[] trainData = null; + final int[] trainData; if (options.getCodebookType() == CompressionOptions.CodebookType.MiddlePlane) { final int middlePlaneIndex = getMiddlePlaneIndex(); diff --git a/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java b/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java index 703beda..e3433a4 100644 --- a/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java +++ b/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java @@ -5,6 +5,7 @@ import cz.it4i.qcmp.cache.SqQvcFile; import cz.it4i.qcmp.compression.exception.ImageDecompressionException; import cz.it4i.qcmp.fileformat.QCMPFileHeader; import cz.it4i.qcmp.huffman.HuffmanDecoder; +import cz.it4i.qcmp.huffman.HuffmanTreeBuilder; import cz.it4i.qcmp.io.InBitStream; import cz.it4i.qcmp.quantization.scalar.SQCodebook; import cz.it4i.qcmp.utilities.Stopwatch; @@ -22,8 +23,7 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I super(options); } - private SQCodebook readScalarQuantizationValues(final DataInputStream compressedStream, - final int codebookSize) throws ImageDecompressionException { + private SQCodebook readSqCodebook(final DataInputStream compressedStream, final int codebookSize) throws ImageDecompressionException { final int[] quantizationValues = new int[codebookSize]; final long[] symbolFrequencies = new long[codebookSize]; try { @@ -36,7 +36,9 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I } catch (final IOException ioEx) { throw new ImageDecompressionException("Unable to read quantization values from compressed stream.", ioEx); } - return new SQCodebook(quantizationValues, symbolFrequencies); + final HuffmanTreeBuilder builder = new HuffmanTreeBuilder(createHuffmanSymbols(codebookSize), symbolFrequencies); + builder.buildHuffmanTree(); + return new SQCodebook(quantizationValues, builder.getRoot()); } @Override @@ -45,7 +47,6 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I final QCMPFileHeader header) throws ImageDecompressionException { final int codebookSize = (int) Math.pow(2, header.getBitsPerCodebookIndex()); - final int[] huffmanSymbols = createHuffmanSymbols(codebookSize); final int planeCountForDecompression = header.getImageSizeZ(); final int planePixelCount = header.getImageSizeX() * header.getImageSizeY(); @@ -55,8 +56,8 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I if (!header.isCodebookPerPlane()) { // There is only one codebook. reportStatusToListeners("Loading single codebook and huffman coder."); - codebook = readScalarQuantizationValues(compressedStream, codebookSize); - huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getSymbolFrequencies()); + codebook = readSqCodebook(compressedStream, codebookSize); + huffmanDecoder = codebook.getHuffmanDecoder(); } final Stopwatch stopwatch = new Stopwatch(); @@ -64,8 +65,8 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I stopwatch.restart(); if (header.isCodebookPerPlane()) { reportStatusToListeners("Loading plane codebook..."); - codebook = readScalarQuantizationValues(compressedStream, codebookSize); - huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getSymbolFrequencies()); + codebook = readSqCodebook(compressedStream, codebookSize); + huffmanDecoder = codebook.getHuffmanDecoder(); } assert (codebook != null && huffmanDecoder != null); @@ -110,8 +111,7 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I final SqQvcFile codebookCache = (SqQvcFile) codebookCacheFile; cachedCodebook = codebookCache.getCodebook(); - cachedHuffmanDecoder = createHuffmanDecoder(createHuffmanSymbols(cachedCodebook.getCodebookSize()), - cachedCodebook.getSymbolFrequencies()); + cachedHuffmanDecoder = cachedCodebook.getHuffmanDecoder(); } @Override @@ -119,7 +119,6 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I final short[][] buffer, final QCMPFileHeader header) throws ImageDecompressionException { final int codebookSize = (int) Math.pow(2, header.getBitsPerCodebookIndex()); - final int[] huffmanSymbols = createHuffmanSymbols(codebookSize); final int planeCountForDecompression = header.getImageSizeZ(); final int planePixelCount = header.getImageSizeX() * header.getImageSizeY(); @@ -128,15 +127,15 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I HuffmanDecoder huffmanDecoder = null; if (!header.isCodebookPerPlane()) { // There is only one codebook. - codebook = readScalarQuantizationValues(compressedStream, codebookSize); - huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getSymbolFrequencies()); + codebook = readSqCodebook(compressedStream, codebookSize); + huffmanDecoder = codebook.getHuffmanDecoder(); } for (int planeIndex = 0; planeIndex < planeCountForDecompression; planeIndex++) { reportProgressToListeners(planeIndex, planeCountForDecompression, "Decompressing plane %d", planeIndex); if (header.isCodebookPerPlane()) { - codebook = readScalarQuantizationValues(compressedStream, codebookSize); - huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getSymbolFrequencies()); + codebook = readSqCodebook(compressedStream, codebookSize); + huffmanDecoder = codebook.getHuffmanDecoder(); } assert (codebook != null && huffmanDecoder != null); diff --git a/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java b/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java index babbf16..b273f83 100644 --- a/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java +++ b/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java @@ -16,7 +16,6 @@ import cz.it4i.qcmp.quantization.vector.VQCodebook; import cz.it4i.qcmp.quantization.vector.VectorQuantizer; import cz.it4i.qcmp.utilities.Stopwatch; import cz.it4i.qcmp.utilities.Utils; -import org.jetbrains.annotations.NotNull; import java.io.DataOutputStream; import java.io.IOException; @@ -36,8 +35,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm public void preloadGlobalCodebook(final IQvcFile codebookCacheFile) { final VQCodebook cachedCodebook = ((VqQvcFile) codebookCacheFile).getCodebook(); cachedQuantizer = new VectorQuantizer(cachedCodebook); - cachedHuffmanEncoder = createHuffmanEncoder(createHuffmanSymbols(cachedCodebook.getCodebookSize()), - cachedCodebook.getVectorFrequencies()); + cachedHuffmanEncoder = cachedCodebook.getHuffmanEncoder(); } public boolean shouldUseKdTree() { @@ -74,6 +72,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm */ private void writeQuantizerToCompressStream(final VectorQuantizer quantizer, final DataOutputStream compressStream) throws ImageCompressionException { + // TODO final int[][] codebook = quantizer.getCodebookVectors(); try { for (final int[] entry : codebook) { @@ -143,7 +142,6 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm return compress1D2DVectors(compressStream, true, inputData); } - @NotNull private long[] compress1D2DVectors(final DataOutputStream compressStream, final boolean streamMode, final InputData inputData) throws ImageCompressionException { @@ -166,7 +164,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm if (options.getCodebookType() == CompressionOptions.CodebookType.Global) { reportStatusToListeners("Loading codebook from cache file."); quantizer = loadQuantizerFromCache(); - huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getFrequencies()); + huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder(); reportStatusToListeners("Cached quantizer with huffman coder created."); writeQuantizerToCompressStream(quantizer, compressStream); } else if (options.getCodebookType() == CompressionOptions.CodebookType.MiddlePlane) { @@ -175,7 +173,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm final int[][] refPlaneVectors = planeLoader.loadVectorsFromPlaneRange(0, options, Utils.singlePlaneRange(getMiddlePlaneIndex())); quantizer = trainVectorQuantizerFromPlaneVectors(refPlaneVectors); - huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getFrequencies()); + huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder(); stopwatch.stop(); reportStatusToListeners("Middle plane codebook created in: " + stopwatch.getElapsedTimeString()); writeQuantizerToCompressStream(quantizer, compressStream); @@ -209,7 +207,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm if (!streamMode && !hasGeneralQuantizer) { reportStatusToListeners(String.format("Training vector quantizer from plane %d.", planeIndex)); quantizer = trainVectorQuantizerFromPlaneVectors(planeVectors); - huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getFrequencies()); + huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder(); writeQuantizerToCompressStream(quantizer, compressStream); } @@ -258,7 +256,6 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm final InputData inputData) throws ImageCompressionException { assert (options.getCodebookType() == CompressionOptions.CodebookType.Global); final IPlaneLoader planeLoader; - final int[] huffmanSymbols = createHuffmanSymbols(getCodebookSize()); try { planeLoader = PlaneLoaderFactory.getPlaneLoaderForInputFile(inputData); planeLoader.setWorkerCount(options.getWorkerCount()); @@ -286,7 +283,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm final VectorQuantizer quantizer = (cachedQuantizer != null) ? cachedQuantizer : loadQuantizerFromCache(); final HuffmanEncoder huffmanEncoder = (cachedHuffmanEncoder != null) ? cachedHuffmanEncoder - : createHuffmanEncoder(huffmanSymbols, quantizer.getFrequencies()); + : quantizer.getCodebook().getHuffmanEncoder(); if (!streamMode) writeQuantizerToCompressStream(quantizer, compressStream); @@ -387,8 +384,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm codebookTrainer.findOptimalCodebook(vqCodebook -> { try { - assert ((vqCodebook.getCodebookSize() == vqCodebook.getVectors().length) && - (vqCodebook.getCodebookSize() == vqCodebook.getVectorFrequencies().length)) + assert (vqCodebook.getCodebookSize() == vqCodebook.getVectors().length) : "Codebook size, Vector count, Frequencies count mismatch"; qcm.saveCodebook(options.getInputDataInfo().getCacheFileName(), vqCodebook); } catch (final IOException e) { diff --git a/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java b/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java index 9262328..65af70f 100644 --- a/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java +++ b/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java @@ -7,6 +7,7 @@ import cz.it4i.qcmp.data.*; import cz.it4i.qcmp.fileformat.QCMPFileHeader; import cz.it4i.qcmp.fileformat.QuantizationType; import cz.it4i.qcmp.huffman.HuffmanDecoder; +import cz.it4i.qcmp.huffman.HuffmanTreeBuilder; import cz.it4i.qcmp.io.InBitStream; import cz.it4i.qcmp.quantization.vector.VQCodebook; import cz.it4i.qcmp.utilities.Stopwatch; @@ -36,8 +37,8 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I } private long calculatePlaneVectorCount(final QCMPFileHeader header) { - final int vectorXCount = (int) Math.ceil((double) header.getImageSizeX() / (double) header.getVectorSizeX()); - final int vectorYCount = (int) Math.ceil((double) header.getImageSizeY() / (double) header.getVectorSizeY()); + final long vectorXCount = (long) Math.ceil((double) header.getImageSizeX() / (double) header.getVectorSizeX()); + final long vectorYCount = (long) Math.ceil((double) header.getImageSizeY() / (double) header.getVectorSizeY()); // Number of vectors per plane. return (vectorXCount * vectorYCount); } @@ -62,8 +63,11 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I throw new ImageDecompressionException("Unable to read quantization values from compressed stream.", ioEx); } + final HuffmanTreeBuilder builder = new HuffmanTreeBuilder(createHuffmanSymbols(codebookSize), frequencies); + builder.buildHuffmanTree(); + // We don't care about vector dimensions in here. - return new VQCodebook(new V3i(0), codebookVectors, frequencies); + return new VQCodebook(new V3i(0), codebookVectors, builder.getRoot()); } @Override @@ -72,8 +76,7 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I final VqQvcFile codebookCache = (VqQvcFile) codebookCacheFile; cachedCodebook = codebookCache.getCodebook(); - cachedHuffmanDecoder = createHuffmanDecoder(createHuffmanSymbols(cachedCodebook.getCodebookSize()), - cachedCodebook.getVectorFrequencies()); + cachedHuffmanDecoder = cachedCodebook.getHuffmanDecoder(); } @@ -118,21 +121,19 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I final int planeCountForDecompression = header.getImageSizeZ(); final long planeVectorCount = calculatePlaneVectorCount(header); final V2i qVector = new V2i(header.getVectorSizeX(), header.getVectorSizeY()); - final int[] huffmanSymbols = createHuffmanSymbols(codebookSize); - VQCodebook codebook = null; HuffmanDecoder huffmanDecoder = null; if (!header.isCodebookPerPlane()) { // There is only one codebook. codebook = readCodebook(compressedStream, codebookSize, vectorSize); - huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getVectorFrequencies()); + huffmanDecoder = codebook.getHuffmanDecoder(); } for (int planeIndex = 0; planeIndex < planeCountForDecompression; planeIndex++) { if (header.isCodebookPerPlane()) { codebook = readCodebook(compressedStream, codebookSize, vectorSize); - huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getVectorFrequencies()); + huffmanDecoder = codebook.getHuffmanDecoder(); } assert (codebook != null && huffmanDecoder != null); @@ -239,7 +240,7 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I final VQCodebook codebook = readCodebook(compressedStream, codebookSize, vectorSize); - final HuffmanDecoder huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getVectorFrequencies()); + final HuffmanDecoder huffmanDecoder = codebook.getHuffmanDecoder(); final int voxelLayerCount = VQImageCompressor.calculateVoxelLayerCount(header.getImageSizeZ(), header.getVectorSizeZ()); final Stopwatch stopwatch = new Stopwatch(); diff --git a/src/main/java/cz/it4i/qcmp/quantization/scalar/LloydMaxU16ScalarQuantization.java b/src/main/java/cz/it4i/qcmp/quantization/scalar/LloydMaxU16ScalarQuantization.java index 0dc3f31..1891503 100644 --- a/src/main/java/cz/it4i/qcmp/quantization/scalar/LloydMaxU16ScalarQuantization.java +++ b/src/main/java/cz/it4i/qcmp/quantization/scalar/LloydMaxU16ScalarQuantization.java @@ -2,6 +2,7 @@ package cz.it4i.qcmp.quantization.scalar; import cz.it4i.qcmp.U16; import cz.it4i.qcmp.compression.listeners.IStatusListener; +import cz.it4i.qcmp.huffman.HuffmanTreeBuilder; import cz.it4i.qcmp.quantization.QTrainIteration; import cz.it4i.qcmp.utilities.MinMaxResult; import cz.it4i.qcmp.utilities.Stopwatch; @@ -258,7 +259,9 @@ public class LloydMaxU16ScalarQuantization { } public SQCodebook getCodebook() { - return new SQCodebook(centroids, frequencies); + final HuffmanTreeBuilder builder = new HuffmanTreeBuilder(codebookSize, frequencies); + builder.buildHuffmanTree(); + return new SQCodebook(centroids, builder.getRoot()); } } diff --git a/src/main/java/cz/it4i/qcmp/quantization/vector/LBGResult.java b/src/main/java/cz/it4i/qcmp/quantization/vector/LBGResult.java index 2bb63af..4d0156e 100644 --- a/src/main/java/cz/it4i/qcmp/quantization/vector/LBGResult.java +++ b/src/main/java/cz/it4i/qcmp/quantization/vector/LBGResult.java @@ -1,6 +1,7 @@ package cz.it4i.qcmp.quantization.vector; import cz.it4i.qcmp.data.V3i; +import cz.it4i.qcmp.huffman.HuffmanTreeBuilder; public class LBGResult { @@ -23,7 +24,9 @@ public class LBGResult { } public VQCodebook getCodebook() { - return new VQCodebook(vectorDims, codebookVectors, frequencies); + final HuffmanTreeBuilder builder = new HuffmanTreeBuilder(codebookVectors.length, frequencies); + builder.buildHuffmanTree(); + return new VQCodebook(vectorDims, codebookVectors, builder.getRoot()); } public double getAverageMse() { diff --git a/src/main/java/cz/it4i/qcmp/quantization/vector/LBGVectorQuantizer.java b/src/main/java/cz/it4i/qcmp/quantization/vector/LBGVectorQuantizer.java index 86d93dc..4f3aa5f 100644 --- a/src/main/java/cz/it4i/qcmp/quantization/vector/LBGVectorQuantizer.java +++ b/src/main/java/cz/it4i/qcmp/quantization/vector/LBGVectorQuantizer.java @@ -3,6 +3,7 @@ package cz.it4i.qcmp.quantization.vector; import cz.it4i.qcmp.U16; import cz.it4i.qcmp.compression.listeners.IStatusListener; import cz.it4i.qcmp.data.V3i; +import cz.it4i.qcmp.huffman.HuffmanTreeBuilder; import cz.it4i.qcmp.utilities.Stopwatch; import cz.it4i.qcmp.utilities.Utils; @@ -207,9 +208,7 @@ public class LBGVectorQuantizer { workers[wId] = new Thread(() -> { final long[] workerFrequencies = new long[codebook.length]; - final VectorQuantizer quantizer = new VectorQuantizer(new VQCodebook(vectorDimensions, - codebook, - frequencies)); + final VectorQuantizer quantizer = new VectorQuantizer(new VQCodebook(vectorDimensions, codebook, null)); double threadMse = 0.0; int[] vector; @@ -245,9 +244,7 @@ public class LBGVectorQuantizer { } mse = _mse / (double) workerCount; } else { - final VectorQuantizer quantizer = new VectorQuantizer(new VQCodebook(vectorDimensions, - codebook, - frequencies)); + final VectorQuantizer quantizer = new VectorQuantizer(new VQCodebook(vectorDimensions, codebook, null)); int qIndex; int[] qVector; for (final TrainingVector trV : trainingVectors) { @@ -412,9 +409,10 @@ public class LBGVectorQuantizer { final long[] codebookFrequencies = new long[codebook.length]; System.arraycopy(frequencies, 0, codebookFrequencies, 0, codebook.length); - codebookFoundCallback.process(new VQCodebook(vectorDimensions, - learningCodebookToCodebook(codebook), - codebookFrequencies)); + + final HuffmanTreeBuilder builder = new HuffmanTreeBuilder(codebook.length, frequencies); + builder.buildHuffmanTree(); + codebookFoundCallback.process(new VQCodebook(vectorDimensions, learningCodebookToCodebook(codebook), builder.getRoot())); } } return codebook; diff --git a/src/main/java/cz/it4i/qcmp/quantization/vector/VQCodebook.java b/src/main/java/cz/it4i/qcmp/quantization/vector/VQCodebook.java index a47f71c..cc618cf 100644 --- a/src/main/java/cz/it4i/qcmp/quantization/vector/VQCodebook.java +++ b/src/main/java/cz/it4i/qcmp/quantization/vector/VQCodebook.java @@ -32,6 +32,7 @@ public class VQCodebook extends Codebook { * @param huffmanRoot Root of the huffman tree. */ public VQCodebook(final V3i vectorDims, final int[][] vectors, final HuffmanNode huffmanRoot) { + super(huffmanRoot); this.vectorDims = vectorDims; this.vectors = vectors; this.codebookSize = vectors.length; diff --git a/src/main/java/cz/it4i/qcmp/quantization/vector/VectorQuantizer.java b/src/main/java/cz/it4i/qcmp/quantization/vector/VectorQuantizer.java index fe73414..639d7ee 100644 --- a/src/main/java/cz/it4i/qcmp/quantization/vector/VectorQuantizer.java +++ b/src/main/java/cz/it4i/qcmp/quantization/vector/VectorQuantizer.java @@ -11,16 +11,15 @@ public class VectorQuantizer { private final VectorDistanceMetric metric = VectorDistanceMetric.Euclidean; private final int[][] codebookVectors; private final int vectorSize; - private final long[] frequencies; + private final VQCodebook codebook; - // private final KDTree kdTree; + // private final KDTree kdTree; public VectorQuantizer(final VQCodebook codebook) { + this.codebook = codebook; this.codebookVectors = codebook.getVectors(); this.vectorSize = codebook.getVectors()[0].length; - this.frequencies = codebook.getVectorFrequencies(); - - // kdTree = new KDTreeBuilder(this.vectorSize, 8).buildTree(codebook.getVectors()); + // kdTree = new KDTreeBuilder(this.vectorSize, 8).buildTree(codebook.getVectors()); } public int[] quantize(final int[] dataVector) { @@ -167,8 +166,8 @@ public class VectorQuantizer { return codebookVectors; } - public long[] getFrequencies() { - return frequencies; + public VQCodebook getCodebook() { + return codebook; } } -- GitLab