Skip to content
Snippets Groups Projects
Commit bce9e5af authored by Vojtech Moravec's avatar Vojtech Moravec
Browse files

Moved vector quantization compression to separate file.

parent 5579ce5f
No related branches found
No related tags found
No related merge requests found
package azgracompress.compression;
import azgracompress.cli.ParsedCliOptions;
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.vector.CodebookEntry;
import azgracompress.quantization.vector.LBGResult;
import azgracompress.quantization.vector.LBGVectorQuantizer;
import azgracompress.quantization.vector.VectorQuantizer;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ImageCompressor extends CompressorDecompressorBase {
......@@ -32,96 +22,37 @@ public class ImageCompressor extends CompressorDecompressorBase {
Log(String.format("Compression with BPP = %d", options.getBitsPerPixel()));
FileOutputStream fos = new FileOutputStream(options.getOutputFile(), false);
DataOutputStream dataOutputStream = new DataOutputStream(new BufferedOutputStream(fos, 8192));
DataOutputStream compressStream = new DataOutputStream(new BufferedOutputStream(fos, 8192));
// Create and write header to output stream.
final QCMPFileHeader header = createHeader();
header.writeHeader(dataOutputStream);
header.writeHeader(compressStream);
boolean compressionResult = true;
switch (options.getQuantizationType()) {
case Scalar: {
SQImageCompressor compressor = new SQImageCompressor(options);
compressor.compress(dataOutputStream);
compressor.compress(compressStream);
}
break;
case Vector1D:
case Vector2D:
compressUsingVectorQuantization(dataOutputStream);
break;
case Vector2D: {
VQImageCompressor compressor = new VQImageCompressor(options);
compressor.compress(compressStream);
}
break;
case Vector3D:
case Invalid:
throw new Exception("Not supported quantization type");
}
dataOutputStream.flush();
compressStream.flush();
fos.flush();
dataOutputStream.close();
compressStream.close();
fos.close();
}
private int[][] getPlaneVectors(final ImageU16 plane) {
final V2i qVector = options.getVectorDimension();
if (qVector.getY() > 1) {
// 2D Quantization.
return Chunk2D.chunksAsImageVectors(plane.as2dChunk().divideIntoChunks(qVector));
} else {
// 1D Quantization.
return plane.as2dChunk().divideInto1DVectors(qVector.getX());
}
}
private VectorQuantizer trainVectorQuantizerFromPlaneVectors(final int[][] planeVectors) {
LBGVectorQuantizer vqInitializer = new LBGVectorQuantizer(planeVectors, codebookSize);
LBGResult vqResult = vqInitializer.findOptimalCodebook(false);
// TODO(Moravec): If verbose ask initializer for result.
return new VectorQuantizer(vqResult.getCodebook());
}
private void compressUsingVectorQuantization(DataOutputStream compressStream) throws Exception {
VectorQuantizer quantizer = null;
if (options.hasReferencePlaneIndex()) {
final ImageU16 referencePlane = RawDataIO.loadImageU16(options.getInputFile(),
options.getImageDimension(),
options.getReferencePlaneIndex());
Log("Creating codebook from reference plane...");
final int[][] refPlaneVectors = getPlaneVectors(referencePlane);
quantizer = trainVectorQuantizerFromPlaneVectors(refPlaneVectors);
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);
final int[][] planeVectors = getPlaneVectors(plane);
if (!options.hasReferencePlaneIndex()) {
Log("Creating plane codebook...");
quantizer = trainVectorQuantizerFromPlaneVectors(planeVectors);
writeCodebookToOutputStream(quantizer, compressStream);
Log("Wrote plane codebook.");
}
assert (quantizer != null);
Log("Writing quantization indices...");
final int[] indices = quantizer.quantizeIntoIndices(planeVectors);
OutBitStream outBitStream = new OutBitStream(compressStream, options.getBitsPerPixel(), 2048);
outBitStream.write(indices);
outBitStream.flush();
Log(String.format("Finished processing of plane %d", planeIndex));
}
}
private QCMPFileHeader createHeader() {
QCMPFileHeader header = new QCMPFileHeader();
......@@ -144,14 +75,5 @@ public class ImageCompressor extends CompressorDecompressorBase {
return header;
}
private void writeCodebookToOutputStream(final VectorQuantizer quantizer,
DataOutputStream compressStream) throws IOException {
final CodebookEntry[] codebook = quantizer.getCodebook();
for (final CodebookEntry entry : codebook) {
final int[] entryVector = entry.getVector();
for (final int vecVal : entryVector) {
compressStream.writeShort(vecVal);
}
}
}
}
......@@ -46,7 +46,7 @@ public class SQImageCompressor extends CompressorDecompressorBase {
}
/**
* Compress the image file specified by parsed CLI options using scalar quantization..
* 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.
......
package azgracompress.compression;
public class VQImageCompressor {
import azgracompress.cli.ParsedCliOptions;
import azgracompress.data.Chunk2D;
import azgracompress.data.ImageU16;
import azgracompress.data.V2i;
import azgracompress.io.OutBitStream;
import azgracompress.io.RawDataIO;
import azgracompress.quantization.vector.CodebookEntry;
import azgracompress.quantization.vector.LBGResult;
import azgracompress.quantization.vector.LBGVectorQuantizer;
import azgracompress.quantization.vector.VectorQuantizer;
import java.io.DataOutputStream;
import java.io.IOException;
public class VQImageCompressor extends CompressorDecompressorBase {
public VQImageCompressor(ParsedCliOptions options) {
super(options);
}
/**
* Get image vectors from the plane. Vector dimensions are specified by parsed CLI options.
*
* @param plane Image plane.
* @return Image vectors.
*/
private int[][] getPlaneVectors(final ImageU16 plane) {
final V2i qVector = options.getVectorDimension();
if (qVector.getY() > 1) {
// 2D Quantization, return `matrices`.
return Chunk2D.chunksAsImageVectors(plane.as2dChunk().divideIntoChunks(qVector));
} else {
// 1D Quantization, return row vectors.
return plane.as2dChunk().divideInto1DVectors(qVector.getX());
}
}
/**
* Train vector quantizer from plane vectors.
*
* @param planeVectors Image vectors.
* @return Trained vector quantizer with codebook of set size.
*/
private VectorQuantizer trainVectorQuantizerFromPlaneVectors(final int[][] planeVectors) {
LBGVectorQuantizer vqInitializer = new LBGVectorQuantizer(planeVectors, codebookSize);
LBGResult vqResult = vqInitializer.findOptimalCodebook(false);
return new VectorQuantizer(vqResult.getCodebook());
}
/**
* Write the vector codebook to the compress stream.
*
* @param quantizer Quantizer with the codebook.
* @param compressStream Stream with compressed data.
* @throws IOException When unable to write quantizer.
*/
private void writeQuantizerToCompressStream(final VectorQuantizer quantizer,
DataOutputStream compressStream) throws IOException {
final CodebookEntry[] codebook = quantizer.getCodebook();
for (final CodebookEntry entry : codebook) {
final int[] entryVector = entry.getVector();
for (final int vecVal : entryVector) {
compressStream.writeShort(vecVal);
}
}
}
/**
* Compress the image file specified by parsed CLI options using vector quantization.
*
* @param compressStream Stream to which compressed data will be written.
* @throws Exception When compress process fails.
*/
public void compress(DataOutputStream compressStream) throws Exception {
VectorQuantizer quantizer = null;
if (options.hasReferencePlaneIndex()) {
final ImageU16 referencePlane = RawDataIO.loadImageU16(options.getInputFile(),
options.getImageDimension(),
options.getReferencePlaneIndex());
Log("Creating codebook from reference plane...");
final int[][] refPlaneVectors = getPlaneVectors(referencePlane);
quantizer = trainVectorQuantizerFromPlaneVectors(refPlaneVectors);
writeQuantizerToCompressStream(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);
final int[][] planeVectors = getPlaneVectors(plane);
if (!options.hasReferencePlaneIndex()) {
Log("Creating plane codebook...");
quantizer = trainVectorQuantizerFromPlaneVectors(planeVectors);
writeQuantizerToCompressStream(quantizer, compressStream);
Log("Wrote plane codebook.");
}
assert (quantizer != null);
Log("Writing quantization indices...");
final int[] indices = quantizer.quantizeIntoIndices(planeVectors);
OutBitStream outBitStream = new OutBitStream(compressStream, options.getBitsPerPixel(), 2048);
outBitStream.write(indices);
outBitStream.flush();
Log(String.format("Finished processing of plane %d", planeIndex));
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment