diff --git a/src/main/java/azgracompress/cache/VQCacheFile.java b/src/main/java/azgracompress/cache/VQCacheFile.java index 3710810e63c48955d4aedd86464df9a256869ec8..986a22a035eae4c238c00e6e7697588cd2f5b9ee 100644 --- a/src/main/java/azgracompress/cache/VQCacheFile.java +++ b/src/main/java/azgracompress/cache/VQCacheFile.java @@ -1,6 +1,5 @@ package azgracompress.cache; -import azgracompress.quantization.vector.CodebookEntry; import azgracompress.quantization.vector.VQCodebook; import java.io.DataInputStream; @@ -23,9 +22,9 @@ public class VQCacheFile implements ICacheFile { public void writeToStream(DataOutputStream outputStream) throws IOException { header.writeToStream(outputStream); - final CodebookEntry[] entries = codebook.getVectors(); - for (final CodebookEntry entry : entries) { - for (final int vectorValue : entry.getVector()) { + final int[][] entries = codebook.getVectors(); + for (final int[] entry : entries) { + for (final int vectorValue : entry) { outputStream.writeShort(vectorValue); } } @@ -45,16 +44,16 @@ public class VQCacheFile implements ICacheFile { @Override public void readFromStream(DataInputStream inputStream, CacheFileHeader header) throws IOException { final int codebookSize = header.getCodebookSize(); - final CodebookEntry[] vectors = new CodebookEntry[codebookSize]; - final long[] frequencies = new long[codebookSize]; final int entrySize = header.getVectorSizeX() * header.getVectorSizeY() * header.getVectorSizeZ(); + final int[][] vectors = new int[codebookSize][entrySize]; + final long[] frequencies = new long[codebookSize]; + for (int i = 0; i < codebookSize; i++) { - int[] vector = new int[entrySize]; + //int[] vector = new int[entrySize]; for (int j = 0; j < entrySize; j++) { - vector[j] = inputStream.readUnsignedShort(); + vectors[i][j] = inputStream.readUnsignedShort(); } - vectors[i] = new CodebookEntry(vector); } for (int i = 0; i < codebookSize; i++) { @@ -73,10 +72,12 @@ public class VQCacheFile implements ICacheFile { @Override public void report(StringBuilder builder) { - final CodebookEntry[] vectors = codebook.getVectors(); - for (int i = 0; i < vectors.length; i++) { + final int[][] vectors = codebook.getVectors(); + for (int[] vector : vectors) { builder.append("- - - - - - - - - - - - - - - - - - - - - - - - -\n"); - vectors[i].getVectorString(builder); + for (final int x : vector) { + builder.append(x).append(';'); + } } } } diff --git a/src/main/java/azgracompress/compression/VQImageCompressor.java b/src/main/java/azgracompress/compression/VQImageCompressor.java index b32a93d272039b770bbfbdc2094085df45a116b5..670a9322c8c770300772dfeb1ed670b95c64221b 100644 --- a/src/main/java/azgracompress/compression/VQImageCompressor.java +++ b/src/main/java/azgracompress/compression/VQImageCompressor.java @@ -47,11 +47,10 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm */ private void writeQuantizerToCompressStream(final VectorQuantizer quantizer, DataOutputStream compressStream) throws ImageCompressionException { - final CodebookEntry[] codebook = quantizer.getCodebookVectors(); + final int[][] codebook = quantizer.getCodebookVectors(); try { - for (final CodebookEntry entry : codebook) { - final int[] entryVector = entry.getVector(); - for (final int vecVal : entryVector) { + for (final int[] entry : codebook) { + for (final int vecVal : entry) { compressStream.writeShort(vecVal); } } @@ -160,7 +159,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm assert (quantizer != null); // Use BestBinFirst KDTree for codebook lookup. -// final int[] indices = quantizer.quantizeIntoIndicesUsingKDTree(planeVectors, options.getWorkerCount()); + // final int[] indices = quantizer.quantizeIntoIndicesUsingKDTree(planeVectors, options.getWorkerCount()); // Use BruteForce for codebook lookup. final int[] indices = quantizer.quantizeIntoIndices(planeVectors, options.getWorkerCount()); diff --git a/src/main/java/azgracompress/compression/VQImageDecompressor.java b/src/main/java/azgracompress/compression/VQImageDecompressor.java index 590fd413ad4699a5d5b45d967ce380000188fc3f..383dea0c4b6ea094497df08a70660a6e4fe1e566 100644 --- a/src/main/java/azgracompress/compression/VQImageDecompressor.java +++ b/src/main/java/azgracompress/compression/VQImageDecompressor.java @@ -7,7 +7,6 @@ import azgracompress.fileformat.QuantizationType; import azgracompress.huffman.Huffman; import azgracompress.huffman.HuffmanNode; import azgracompress.io.InBitStream; -import azgracompress.quantization.vector.CodebookEntry; import azgracompress.quantization.vector.VQCodebook; import azgracompress.utilities.Stopwatch; import azgracompress.utilities.TypeConverter; @@ -48,15 +47,14 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I final int codebookSize, final int vectorSize) throws ImageDecompressionException { - final CodebookEntry[] codebookVectors = new CodebookEntry[codebookSize]; + final int[][] codebookVectors = new int[codebookSize][vectorSize]; final long[] frequencies = new long[codebookSize]; try { for (int codebookIndex = 0; codebookIndex < codebookSize; codebookIndex++) { - final int[] vector = new int[vectorSize]; + // final int[] vector = new int[vectorSize]; for (int vecIndex = 0; vecIndex < vectorSize; vecIndex++) { - vector[vecIndex] = compressedStream.readUnsignedShort(); + codebookVectors[codebookIndex][vecIndex] = compressedStream.readUnsignedShort(); } - codebookVectors[codebookIndex] = new CodebookEntry(vector); } for (int codebookIndex = 0; codebookIndex < codebookSize; codebookIndex++) { frequencies[codebookIndex] = compressedStream.readLong(); @@ -166,7 +164,7 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I bit = inBitStream.readBit(); currentHuffmanNode = currentHuffmanNode.traverse(bit); } - System.arraycopy(codebook.getVectors()[currentHuffmanNode.getSymbol()].getVector(), + System.arraycopy(codebook.getVectors()[currentHuffmanNode.getSymbol()], 0, decompressedVectors[vecIndex], 0, vectorSize); } @@ -239,7 +237,7 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I for (int voxelIndex = 0; voxelIndex < voxelLayerVoxelCount; voxelIndex++) { final int huffmanSymbol = decodeHuffmanSymbol(huffman, inBitStream); - System.arraycopy(codebook.getVectors()[huffmanSymbol].getVector(), 0, decompressedVoxels[voxelIndex], 0, vectorSize); + System.arraycopy(codebook.getVectors()[huffmanSymbol], 0, decompressedVoxels[voxelIndex], 0, vectorSize); } } catch (Exception e) { diff --git a/src/main/java/azgracompress/quantization/vector/CodebookEntry.java b/src/main/java/azgracompress/quantization/vector/CodebookEntry.java deleted file mode 100644 index 72cf8648d097fabca1b06a1a96bdf4dae46afc45..0000000000000000000000000000000000000000 --- a/src/main/java/azgracompress/quantization/vector/CodebookEntry.java +++ /dev/null @@ -1,58 +0,0 @@ -package azgracompress.quantization.vector; - -public class CodebookEntry { - - final int[] vector; - final int width; - final int height; - - public CodebookEntry(final int[] codebook) { - - this.vector = codebook; - this.width = codebook.length; - this.height = 1; - } - - @Override - public boolean equals(final Object obj) { - if (obj instanceof CodebookEntry) { - final CodebookEntry ceObj = (CodebookEntry) obj; - if (vector.length != ceObj.vector.length) { - return false; - } - for (int i = 0; i < vector.length; i++) { - if (vector[i] != ceObj.vector[i]) { - return false; - } - } - return true; - } - return super.equals(obj); - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public int[] getVector() { - return vector; - } - - public String getVectorString(StringBuilder sb) { - for (int i = 0; i < vector.length; i++) { - sb.append(vector[i]); - if (i != (vector.length - 1)) - sb.append(';'); - } - sb.append('\n'); - return sb.toString(); - } - - public String getVectorString() { - return getVectorString(new StringBuilder()); - } -} diff --git a/src/main/java/azgracompress/quantization/vector/LBGResult.java b/src/main/java/azgracompress/quantization/vector/LBGResult.java index da4a27c5064defbe180639aff5e8c32a9f34e2d2..4b72a79698c4241f4447ac50314f54829553f49d 100644 --- a/src/main/java/azgracompress/quantization/vector/LBGResult.java +++ b/src/main/java/azgracompress/quantization/vector/LBGResult.java @@ -4,14 +4,14 @@ import azgracompress.data.V3i; public class LBGResult { - private final CodebookEntry[] codebookVectors; + private final int[][] codebookVectors; private final long[] frequencies; private final double averageMse; private final double psnr; private final V3i vectorDims; public LBGResult(final V3i vectorDims, - final CodebookEntry[] codebook, + final int[][] codebook, final long[] frequencies, final double averageMse, final double psnr) { diff --git a/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java b/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java index b431e3f5659e745850e55dfdee8ea8e3c5cfa786..0ad49cfe228318c31965150924253292089dda80 100644 --- a/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java +++ b/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java @@ -92,13 +92,12 @@ public class LBGVectorQuantizer { assert (uniqueTrainingVectors != null) : "uniqueTrainingVectors aren't initialized."; reportStatus("There is only %d unique vectors. Creating codebook from unique vectors...", uniqueTrainingVectors.size()); - CodebookEntry[] codebook = new CodebookEntry[codebookSize]; - int[] zeros = new int[vectorSize]; - Arrays.fill(zeros, 0); - CodebookEntry zeroEntry = new CodebookEntry(zeros); + final int[][] codebook = new int[codebookSize][vectorSize]; + int[] zeroEntry = new int[vectorSize]; + Arrays.fill(zeroEntry, 0); for (int i = 0; i < codebookSize; i++) { if (i < uniqueVectorCount) { - codebook[i] = new CodebookEntry(uniqueTrainingVectors.get(i).getVector()); + codebook[i] = uniqueTrainingVectors.get(i).getVector(); } else { codebook[i] = zeroEntry; } @@ -141,10 +140,10 @@ public class LBGVectorQuantizer { * @param learningCodebook Source array of LearningCodebookEntry. * @return Array of CodebookEntries. */ - private CodebookEntry[] learningCodebookToCodebook(final LearningCodebookEntry[] learningCodebook) { - CodebookEntry[] codebook = new CodebookEntry[learningCodebook.length]; + private int[][] learningCodebookToCodebook(final LearningCodebookEntry[] learningCodebook) { + final int[][] codebook = new int[learningCodebook.length][vectorSize]; for (int i = 0; i < codebook.length; i++) { - codebook[i] = new CodebookEntry(learningCodebook[i].getVector()); + codebook[i] = learningCodebook[i].getVector(); } return codebook; } @@ -168,14 +167,17 @@ public class LBGVectorQuantizer { } } + private double averageMse(final LearningCodebookEntry[] codebook) { + return averageMse(learningCodebookToCodebook(codebook)); + } + /** * Calculate the average mean square error of the codebook. * * @param codebook Codebook of vectors. * @return Mean square error. */ - private double averageMse(final CodebookEntry[] codebook) { - Stopwatch s = Stopwatch.startNew("averageMse"); + private double averageMse(final int[][] codebook) { double mse = 0.0; resetFrequencies(); if (workerCount > 1) { @@ -202,7 +204,8 @@ public class LBGVectorQuantizer { qIndex = quantizer.quantizeToIndex(vector); ++workerFrequencies[qIndex]; - qVector = quantizer.getCodebookVectors()[qIndex].getVector(); + + qVector = quantizer.getCodebookVectors()[qIndex]; for (int vI = 0; vI < vectorSize; vI++) { threadMse += Math.pow(((double) vector[vI] - (double) qVector[vI]), 2); } @@ -233,7 +236,7 @@ public class LBGVectorQuantizer { int[] qVector; for (final TrainingVector trV : trainingVectors) { qIndex = quantizer.quantizeToIndex(trV.getVector()); - qVector = quantizer.getCodebookVectors()[qIndex].getVector(); + qVector = quantizer.getCodebookVectors()[qIndex]; ++frequencies[qIndex]; for (int i = 0; i < vectorSize; i++) { mse += Math.pow(((double) trV.getVector()[i] - (double) qVector[i]), 2); @@ -241,10 +244,6 @@ public class LBGVectorQuantizer { } mse /= (double) trainingVectors.length; } - s.stop(); - // if (this.verbose) { - //// System.out.println(s); - // } return mse; } diff --git a/src/main/java/azgracompress/quantization/vector/LearningCodebookEntry.java b/src/main/java/azgracompress/quantization/vector/LearningCodebookEntry.java index 30cbee3d2bb3fe687d889b1e9d9b866906d86bfd..4492e4c90d83658d9512a16e341660bd887e4117 100644 --- a/src/main/java/azgracompress/quantization/vector/LearningCodebookEntry.java +++ b/src/main/java/azgracompress/quantization/vector/LearningCodebookEntry.java @@ -1,31 +1,36 @@ package azgracompress.quantization.vector; -public class LearningCodebookEntry extends CodebookEntry { +public class LearningCodebookEntry { + private final int[] codebookVector; private int vectorCount = -1; private double averageDistortion = -1.0f; private double[] perturbationVector; - public LearningCodebookEntry(int[] codebook) { - super(codebook); + public LearningCodebookEntry(int[] codebookVector) { + this.codebookVector = codebookVector; } /** * Set codebook entry properties from helper object. * - * @param info Helper object with property informations. + * @param info Helper object with property information. */ public void setInfo(final EntryInfo info) { this.vectorCount = info.vectorCount; this.averageDistortion = info.calculateAverageDistortion(); final int[] newCentroid = info.calculateCentroid(); - assert (newCentroid.length == vector.length); - System.arraycopy(newCentroid, 0, this.vector, 0, newCentroid.length); + assert (newCentroid.length == codebookVector.length); + System.arraycopy(newCentroid, 0, this.codebookVector, 0, newCentroid.length); this.perturbationVector = info.calculatePRTVector(); } + public int[] getVector() { + return codebookVector; + } + /** * Get perturbation vector for splitting this entry. * diff --git a/src/main/java/azgracompress/quantization/vector/VQCodebook.java b/src/main/java/azgracompress/quantization/vector/VQCodebook.java index 1afb8d2274d81aa703df336b0ce86c18e86e2dcf..d56fc6b3d611d92f5493fb64ca2119b6e7e1f17f 100644 --- a/src/main/java/azgracompress/quantization/vector/VQCodebook.java +++ b/src/main/java/azgracompress/quantization/vector/VQCodebook.java @@ -9,7 +9,7 @@ public class VQCodebook { /** * Quantization vectors. */ - private final CodebookEntry[] vectors; + private final int[][] vectors; /** * Absolute frequencies of quantization vectors. @@ -26,7 +26,7 @@ public class VQCodebook { */ private final V3i vectorDims; - public VQCodebook(final V3i vectorDims, final CodebookEntry[] vectors, final long[] vectorFrequencies) { + public VQCodebook(final V3i vectorDims, final int[][] vectors, final long[] vectorFrequencies) { //assert (vectors.length == vectorFrequencies.length); this.vectorDims = vectorDims; this.vectors = vectors; @@ -39,20 +39,10 @@ public class VQCodebook { * * @return Quantization vectors. */ - public CodebookEntry[] getVectors() { + public int[][] getVectors() { return vectors; } - public int[][] getRawVectors() { - assert (codebookSize == vectors.length); - assert (vectors[0].getVector().length == (int) vectorDims.multiplyTogether()); - final int[][] rawCodebook = new int[vectors.length][(int) vectorDims.multiplyTogether()]; - for (int i = 0; i < codebookSize; i++) { - rawCodebook[i] = vectors[i].getVector(); - } - return rawCodebook; - } - /** * Get frequencies of codebook vectors at indices. * diff --git a/src/main/java/azgracompress/quantization/vector/VectorQuantizer.java b/src/main/java/azgracompress/quantization/vector/VectorQuantizer.java index 4fcc8caa6eb4d1b9f53f6989c58c305325091627..efca6ebb9b8bfd27a0c1afb205ebcfbaf9e87469 100644 --- a/src/main/java/azgracompress/quantization/vector/VectorQuantizer.java +++ b/src/main/java/azgracompress/quantization/vector/VectorQuantizer.java @@ -11,7 +11,7 @@ public class VectorQuantizer { } private final VectorDistanceMetric metric = VectorDistanceMetric.Euclidean; - private final CodebookEntry[] codebookVectors; + private final int[][] codebookVectors; private final int vectorSize; private final long[] frequencies; @@ -19,16 +19,15 @@ public class VectorQuantizer { public VectorQuantizer(final VQCodebook codebook) { this.codebookVectors = codebook.getVectors(); - this.vectorSize = codebookVectors[0].getVector().length; + this.vectorSize = codebook.getVectors()[0].length; this.frequencies = codebook.getVectorFrequencies(); - kdTree = new KDTreeBuilder(this.vectorSize, 8).buildTree(codebook.getRawVectors()); + kdTree = new KDTreeBuilder(this.vectorSize, 8).buildTree(codebook.getVectors()); } public int[] quantize(final int[] dataVector) { assert (dataVector.length > 0 && dataVector.length % vectorSize == 0) : "Wrong vector size"; - final CodebookEntry closestEntry = findClosestCodebookEntry(dataVector, metric); - return closestEntry.getVector(); + return findClosestCodebookEntry(dataVector, metric); } public int quantizeToIndex(final int[] dataVector) { @@ -42,13 +41,12 @@ public class VectorQuantizer { if (workerCount == 1) { for (int vectorIndex = 0; vectorIndex < dataVectors.length; vectorIndex++) { - final CodebookEntry closestEntry = findClosestCodebookEntry(dataVectors[vectorIndex], metric); - result[vectorIndex] = closestEntry.getVector(); + result[vectorIndex] = findClosestCodebookEntry(dataVectors[vectorIndex], metric); } } else { final int[] indices = quantizeIntoIndices(dataVectors, workerCount); for (int i = 0; i < dataVectors.length; i++) { - result[i] = codebookVectors[indices[i]].getVector(); + result[i] = codebookVectors[indices[i]]; } } @@ -142,11 +140,11 @@ public class VectorQuantizer { return 0.0; } - private CodebookEntry findClosestCodebookEntry(final int[] dataVector) { + private int[] findClosestCodebookEntry(final int[] dataVector) { return findClosestCodebookEntry(dataVector, metric); } - private CodebookEntry findClosestCodebookEntry(final int[] dataVector, final VectorDistanceMetric metric) { + private int[] findClosestCodebookEntry(final int[] dataVector, final VectorDistanceMetric metric) { return codebookVectors[findClosestCodebookEntryIndex(dataVector, metric)]; } @@ -156,7 +154,7 @@ public class VectorQuantizer { for (int entryIndex = 0; entryIndex < codebookVectors.length; entryIndex++) { - final double dist = distanceBetweenVectors(dataVector, codebookVectors[entryIndex].getVector(), metric); + final double dist = distanceBetweenVectors(dataVector, codebookVectors[entryIndex], metric); if (dist < minDist) { minDist = dist; closestEntryIndex = entryIndex; @@ -166,7 +164,7 @@ public class VectorQuantizer { return closestEntryIndex; } - public CodebookEntry[] getCodebookVectors() { + public int[][] getCodebookVectors() { return codebookVectors; }