diff --git a/src/main/java/azgracompress/compression/CompressorDecompressorBase.java b/src/main/java/azgracompress/compression/CompressorDecompressorBase.java index e91e4ff0a2dde7065d2887dd161a5c464d0b4f27..9b16a04b3c9689a1bc28f7aabadca395fba08372 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 cea032642f4eb9a275615c679d12184ad56a99cf..9f0ed92889886b34ca612f49e23fd08a3be5ba59 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 0000000000000000000000000000000000000000..fd5a59e61f7b8def46d732f32ff438929c09011d --- /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 0000000000000000000000000000000000000000..cfb69b8ea0072a5f59d5b66288a9a91dda5713c8 --- /dev/null +++ b/src/main/java/azgracompress/compression/VQImageCompressor.java @@ -0,0 +1,4 @@ +package azgracompress.compression; + +public class VQImageCompressor { +}