From 5579ce5fedc0b1a80d0dfd2db59cb03c5566d813 Mon Sep 17 00:00:00 2001 From: Vojtech Moravec <vojtech.moravec.st@vsb.cz> Date: Sat, 18 Jan 2020 15:48:11 +0100 Subject: [PATCH] Moved scalar quantization compression to separate file. --- .../CompressorDecompressorBase.java | 2 + .../compression/ImageCompressor.java | 67 +------------- .../compression/SQImageCompressor.java | 92 +++++++++++++++++++ .../compression/VQImageCompressor.java | 4 + 4 files changed, 103 insertions(+), 62 deletions(-) create mode 100644 src/main/java/azgracompress/compression/SQImageCompressor.java create mode 100644 src/main/java/azgracompress/compression/VQImageCompressor.java diff --git a/src/main/java/azgracompress/compression/CompressorDecompressorBase.java b/src/main/java/azgracompress/compression/CompressorDecompressorBase.java index e91e4ff..9b16a04 100644 --- a/src/main/java/azgracompress/compression/CompressorDecompressorBase.java +++ b/src/main/java/azgracompress/compression/CompressorDecompressorBase.java @@ -6,9 +6,11 @@ public abstract class CompressorDecompressorBase { public static final String EXTENSTION = ".QCMP"; protected final ParsedCliOptions options; + protected final int codebookSize; public CompressorDecompressorBase(ParsedCliOptions options) { this.options = options; + this.codebookSize = (int) Math.pow(2, this.options.getBitsPerPixel()); } protected int[] getPlaneIndicesForCompression() { diff --git a/src/main/java/azgracompress/compression/ImageCompressor.java b/src/main/java/azgracompress/compression/ImageCompressor.java index cea0326..9f0ed92 100644 --- a/src/main/java/azgracompress/compression/ImageCompressor.java +++ b/src/main/java/azgracompress/compression/ImageCompressor.java @@ -1,15 +1,12 @@ package azgracompress.compression; import azgracompress.cli.ParsedCliOptions; -import azgracompress.U16; import azgracompress.data.Chunk2D; import azgracompress.data.ImageU16; import azgracompress.data.V2i; import azgracompress.fileformat.QCMPFileHeader; import azgracompress.io.OutBitStream; import azgracompress.io.RawDataIO; -import azgracompress.quantization.scalar.LloydMaxU16ScalarQuantization; -import azgracompress.quantization.scalar.ScalarQuantizer; import azgracompress.quantization.vector.CodebookEntry; import azgracompress.quantization.vector.LBGResult; import azgracompress.quantization.vector.LBGVectorQuantizer; @@ -43,9 +40,11 @@ public class ImageCompressor extends CompressorDecompressorBase { boolean compressionResult = true; switch (options.getQuantizationType()) { - case Scalar: - compressUsingScalarQuantization(dataOutputStream); - break; + case Scalar: { + SQImageCompressor compressor = new SQImageCompressor(options); + compressor.compress(dataOutputStream); + } + break; case Vector1D: case Vector2D: compressUsingVectorQuantization(dataOutputStream); @@ -62,14 +61,6 @@ public class ImageCompressor extends CompressorDecompressorBase { fos.close(); } - - private ScalarQuantizer getScalarQuantizerFromPlane(final ImageU16 plane) { - - LloydMaxU16ScalarQuantization lloydMax = new LloydMaxU16ScalarQuantization(plane.getData(), codebookSize); - lloydMax.train(false); - return new ScalarQuantizer(U16.Min, U16.Max, lloydMax.getCentroids()); - } - private int[][] getPlaneVectors(final ImageU16 plane) { final V2i qVector = options.getVectorDimension(); @@ -153,14 +144,6 @@ public class ImageCompressor extends CompressorDecompressorBase { return header; } - private void writeCodebookToOutputStream(final ScalarQuantizer quantizer, - DataOutputStream compressStream) throws IOException { - final int[] centroids = quantizer.getCentroids(); - for (final int quantizationValue : centroids) { - compressStream.writeShort(quantizationValue); - } - } - private void writeCodebookToOutputStream(final VectorQuantizer quantizer, DataOutputStream compressStream) throws IOException { final CodebookEntry[] codebook = quantizer.getCodebook(); @@ -171,44 +154,4 @@ public class ImageCompressor extends CompressorDecompressorBase { } } } - - - private void compressUsingScalarQuantization(DataOutputStream compressStream) throws Exception { - ScalarQuantizer quantizer = null; - if (options.hasReferencePlaneIndex()) { - final ImageU16 referencePlane = RawDataIO.loadImageU16(options.getInputFile(), - options.getImageDimension(), - options.getReferencePlaneIndex()); - - Log("Creating codebook from reference plane..."); - quantizer = getScalarQuantizerFromPlane(referencePlane); - writeCodebookToOutputStream(quantizer, compressStream); - Log("Wrote reference codebook."); - } - - final int[] planeIndices = getPlaneIndicesForCompression(); - - for (final int planeIndex : planeIndices) { - Log(String.format("Loading plane %d...", planeIndex)); - final ImageU16 plane = RawDataIO.loadImageU16(options.getInputFile(), - options.getImageDimension(), - planeIndex); - - if (!options.hasReferencePlaneIndex()) { - Log("Creating plane codebook..."); - quantizer = getScalarQuantizerFromPlane(plane); - writeCodebookToOutputStream(quantizer, compressStream); - Log("Wrote plane codebook."); - } - - assert (quantizer != null); - - Log("Writing quantization indices..."); - final int[] indices = quantizer.quantizeIntoIndices(plane.getData()); - OutBitStream outBitStream = new OutBitStream(compressStream, options.getBitsPerPixel(), 2048); - outBitStream.write(indices); - outBitStream.flush(); - Log(String.format("Finished processing of plane %d", planeIndex)); - } - } } diff --git a/src/main/java/azgracompress/compression/SQImageCompressor.java b/src/main/java/azgracompress/compression/SQImageCompressor.java new file mode 100644 index 0000000..fd5a59e --- /dev/null +++ b/src/main/java/azgracompress/compression/SQImageCompressor.java @@ -0,0 +1,92 @@ +package azgracompress.compression; + +import azgracompress.U16; +import azgracompress.cli.ParsedCliOptions; +import azgracompress.data.ImageU16; +import azgracompress.io.OutBitStream; +import azgracompress.io.RawDataIO; +import azgracompress.quantization.scalar.LloydMaxU16ScalarQuantization; +import azgracompress.quantization.scalar.ScalarQuantizer; + +import java.io.DataOutputStream; +import java.io.IOException; + +public class SQImageCompressor extends CompressorDecompressorBase { + + public SQImageCompressor(ParsedCliOptions options) { + super(options); + + } + + /** + * Train Lloyd-Max scalar quantizer from plane data. + * + * @param planeData Plane data from which quantizer will be trained. + * @return Trained scalar quantizer. + */ + private ScalarQuantizer trainScalarQuantizerFromData(final short[] planeData) { + LloydMaxU16ScalarQuantization lloydMax = new LloydMaxU16ScalarQuantization(planeData, codebookSize); + lloydMax.train(false); + return new ScalarQuantizer(U16.Min, U16.Max, lloydMax.getCentroids()); + } + + /** + * Writes the scalar quantizer to the compressed stream. + * + * @param quantizer Quantizer used for compression of the image. + * @param compressStream Compressed data stream. + * @throws IOException when writing to the stream fails. + */ + private void writeCodebookToOutputStream(final ScalarQuantizer quantizer, + DataOutputStream compressStream) throws IOException { + final int[] centroids = quantizer.getCentroids(); + for (final int quantizationValue : centroids) { + compressStream.writeShort(quantizationValue); + } + } + + /** + * Compress the image file specified by parsed CLI options using scalar quantization.. + * + * @param compressStream Stream to which compressed data will be written. + * @throws Exception When compress process fails. + */ + public void compress(DataOutputStream compressStream) throws Exception { + ScalarQuantizer quantizer = null; + if (options.hasReferencePlaneIndex()) { + final ImageU16 referencePlane = RawDataIO.loadImageU16(options.getInputFile(), + options.getImageDimension(), + options.getReferencePlaneIndex()); + + Log("Creating codebook from reference plane..."); + quantizer = trainScalarQuantizerFromData(referencePlane.getData()); + writeCodebookToOutputStream(quantizer, compressStream); + Log("Wrote reference codebook."); + } + + final int[] planeIndices = getPlaneIndicesForCompression(); + + for (final int planeIndex : planeIndices) { + Log(String.format("Loading plane %d...", planeIndex)); + final ImageU16 plane = RawDataIO.loadImageU16(options.getInputFile(), + options.getImageDimension(), + planeIndex); + + if (!options.hasReferencePlaneIndex()) { + Log("Creating plane codebook..."); + quantizer = trainScalarQuantizerFromData(plane.getData()); + writeCodebookToOutputStream(quantizer, compressStream); + Log("Wrote plane codebook."); + } + + assert (quantizer != null); + + Log("Writing quantization indices..."); + final int[] indices = quantizer.quantizeIntoIndices(plane.getData()); + OutBitStream outBitStream = new OutBitStream(compressStream, options.getBitsPerPixel(), 2048); + outBitStream.write(indices); + outBitStream.flush(); + Log(String.format("Finished processing of plane %d", planeIndex)); + } + } +} diff --git a/src/main/java/azgracompress/compression/VQImageCompressor.java b/src/main/java/azgracompress/compression/VQImageCompressor.java new file mode 100644 index 0000000..cfb69b8 --- /dev/null +++ b/src/main/java/azgracompress/compression/VQImageCompressor.java @@ -0,0 +1,4 @@ +package azgracompress.compression; + +public class VQImageCompressor { +} -- GitLab