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

Add variant of quantizeIntoIndices with KDTree lookup.

In early experiments BBF algorithm with low maxE value is faster than
conventional brute force search for dimensions up to 27 (3x3x3).

VQImageCompressor still uses the old method but it can be switched
easily in the code.
parent 4d09dc3b
No related branches found
No related tags found
No related merge requests found
...@@ -159,6 +159,9 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm ...@@ -159,6 +159,9 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
assert (quantizer != null); assert (quantizer != null);
// Use BestBinFirst KDTree for codebook lookup.
// final int[] indices = quantizer.quantizeIntoIndicesUsingKDTree(planeVectors, options.getWorkerCount());
// Use BruteForce for codebook lookup.
final int[] indices = quantizer.quantizeIntoIndices(planeVectors, options.getWorkerCount()); final int[] indices = quantizer.quantizeIntoIndices(planeVectors, options.getWorkerCount());
planeDataSizes[planeCounter++] = writeHuffmanEncodedIndices(compressStream, huffman, indices); planeDataSizes[planeCounter++] = writeHuffmanEncodedIndices(compressStream, huffman, indices);
......
...@@ -6,6 +6,10 @@ import azgracompress.utilities.Utils; ...@@ -6,6 +6,10 @@ import azgracompress.utilities.Utils;
public class VectorQuantizer { public class VectorQuantizer {
private interface QuantizeVectorMethod {
int call(final int[] vector);
}
private final VectorDistanceMetric metric = VectorDistanceMetric.Euclidean; private final VectorDistanceMetric metric = VectorDistanceMetric.Euclidean;
private final CodebookEntry[] codebookVectors; private final CodebookEntry[] codebookVectors;
private final int vectorSize; private final int vectorSize;
...@@ -55,26 +59,16 @@ public class VectorQuantizer { ...@@ -55,26 +59,16 @@ public class VectorQuantizer {
return quantizeIntoIndices(dataVectors, 1); return quantizeIntoIndices(dataVectors, 1);
} }
public int[] quantizeIntoIndicesUsingKDTree(final int[][] dataVectors, final int maxWorkerCount) { private int[] quantizeIntoIndicesImpl(final int[][] dataVectors,
assert (dataVectors.length > 0 && dataVectors[0].length % vectorSize == 0) : "Wrong vector size"; final int maxWorkerCount,
int[] indices = new int[dataVectors.length]; final QuantizeVectorMethod method) {
for (int vectorIndex = 0; vectorIndex < dataVectors.length; vectorIndex++) {
indices[vectorIndex] = kdTree.findNearestBBF(dataVectors[vectorIndex], 32); assert (dataVectors.length > 0 && dataVectors[0].length == vectorSize) : "Wrong vector size";
}
return indices;
}
public int[] quantizeIntoIndices(final int[][] dataVectors, final int maxWorkerCount) {
assert (dataVectors.length > 0 && dataVectors[0].length % vectorSize == 0) : "Wrong vector size";
int[] indices = new int[dataVectors.length]; int[] indices = new int[dataVectors.length];
if (maxWorkerCount == 1) { if (maxWorkerCount == 1) {
int closestIndex;
for (int vectorIndex = 0; vectorIndex < dataVectors.length; vectorIndex++) { for (int vectorIndex = 0; vectorIndex < dataVectors.length; vectorIndex++) {
closestIndex = findClosestCodebookEntryIndex(dataVectors[vectorIndex], metric); indices[vectorIndex] = method.call(dataVectors[vectorIndex]);
indices[vectorIndex] = closestIndex;
} }
} else { } else {
// Cap the worker count on 8 // Cap the worker count on 8
...@@ -86,12 +80,9 @@ public class VectorQuantizer { ...@@ -86,12 +80,9 @@ public class VectorQuantizer {
final int fromIndex = wId * workSize; final int fromIndex = wId * workSize;
final int toIndex = (wId == workerCount - 1) ? dataVectors.length : (workSize + (wId * workSize)); final int toIndex = (wId == workerCount - 1) ? dataVectors.length : (workSize + (wId * workSize));
workers[wId] = new Thread(() -> { workers[wId] = new Thread(() -> {
int closestIndex;
for (int vectorIndex = fromIndex; vectorIndex < toIndex; vectorIndex++) { for (int vectorIndex = fromIndex; vectorIndex < toIndex; vectorIndex++) {
closestIndex = findClosestCodebookEntryIndex(dataVectors[vectorIndex], metric); indices[vectorIndex] = method.call(dataVectors[vectorIndex]);
indices[vectorIndex] = closestIndex;
} }
}); });
...@@ -104,11 +95,23 @@ public class VectorQuantizer { ...@@ -104,11 +95,23 @@ public class VectorQuantizer {
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
return indices; return indices;
} }
public int[] quantizeIntoIndicesUsingKDTree(final int[][] dataVectors, final int maxWorkerCount) {
return quantizeIntoIndicesImpl(dataVectors, maxWorkerCount, (final int[] queryVector) ->
kdTree.findNearestBBF(queryVector, 8));
}
public int[] quantizeIntoIndices(final int[][] dataVectors, final int maxWorkerCount) {
return quantizeIntoIndicesImpl(dataVectors, maxWorkerCount, (final int[] queryVector) ->
findClosestCodebookEntryIndex(queryVector, metric));
}
public static double distanceBetweenVectors(final int[] originalDataVector, public static double distanceBetweenVectors(final int[] originalDataVector,
final int[] codebookEntry, final int[] codebookEntry,
final VectorDistanceMetric metric) { final VectorDistanceMetric metric) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment