diff --git a/src/main/java/azgracompress/compression/CompressionOptions.java b/src/main/java/azgracompress/compression/CompressionOptions.java
index 82e7c5c61bf4d1aacf946f74f49d6ef3d41c4113..09c83fb5d3395150cd175f0d1de813dd28163321 100644
--- a/src/main/java/azgracompress/compression/CompressionOptions.java
+++ b/src/main/java/azgracompress/compression/CompressionOptions.java
@@ -67,7 +67,7 @@ public class CompressionOptions {
this.workerCount = (cores / 2);
}
- protected void setVerbose(boolean verbose) {
+ public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
diff --git a/src/main/java/azgracompress/compression/VQImageCompressor.java b/src/main/java/azgracompress/compression/VQImageCompressor.java
index 05539c6f994ba04f0ce8ca5327701d2607b7187c..4543ed9b2e6702f01f81d612dbea4bafe76317d1 100644
--- a/src/main/java/azgracompress/compression/VQImageCompressor.java
+++ b/src/main/java/azgracompress/compression/VQImageCompressor.java
@@ -32,7 +32,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
getCodebookSize(),
options.getWorkerCount(),
options.getVectorDimension().toV3i());
- LBGResult vqResult = vqInitializer.findOptimalCodebook(false);
+ LBGResult vqResult = vqInitializer.findOptimalCodebook();
return new VectorQuantizer(vqResult.getCodebook());
}
@@ -255,7 +255,8 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
options.getWorkerCount(),
options.getVectorDimension().toV3i());
reportStatusToListeners("Starting LBG optimization.");
- LBGResult lbgResult = vqInitializer.findOptimalCodebook(options.isVerbose());
+ vqInitializer.setStatusListener(this::reportStatusToListeners);
+ LBGResult lbgResult = vqInitializer.findOptimalCodebook();
reportStatusToListeners("Learned the optimal codebook.");
diff --git a/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java b/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java
index 6943a3edd8411a09c2eea8e1a683f812c33e063f..b431e3f5659e745850e55dfdee8ea8e3c5cfa786 100644
--- a/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java
+++ b/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java
@@ -1,6 +1,7 @@
package azgracompress.quantization.vector;
import azgracompress.U16;
+import azgracompress.compression.listeners.IStatusListener;
import azgracompress.data.V3i;
import azgracompress.utilities.Stopwatch;
import azgracompress.utilities.Utils;
@@ -24,7 +25,7 @@ public class LBGVectorQuantizer {
private long[] frequencies;
- boolean verbose = false;
+ private IStatusListener statusListener = null;
private double _mse = 0.0;
public LBGVectorQuantizer(final int[][] vectors,
@@ -49,6 +50,19 @@ public class LBGVectorQuantizer {
findUniqueVectors();
}
+ public void setStatusListener(final IStatusListener statusListener) {
+ this.statusListener = statusListener;
+ }
+
+ private void reportStatus(final String message) {
+ if (statusListener != null)
+ statusListener.sendMessage(message);
+ }
+
+ private void reportStatus(final String format, final Object... arg) {
+ reportStatus(String.format(format, arg));
+ }
+
private void findUniqueVectors() {
uniqueVectorCount = 0;
uniqueTrainingVectors = new ArrayList<>(codebookSize);
@@ -74,10 +88,10 @@ public class LBGVectorQuantizer {
}
private LBGResult createCodebookFromUniqueVectors() {
+
assert (uniqueTrainingVectors != null) : "uniqueTrainingVectors aren't initialized.";
- if (verbose) {
- System.out.println("Creating codebook from unique vectors.");
- }
+ 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);
@@ -91,9 +105,7 @@ public class LBGVectorQuantizer {
}
final double mse = averageMse(codebook);
final double psnr = Utils.calculatePsnr(mse, U16.Max);
- if (verbose) {
- System.out.println(String.format("Final MSE: %.4f\nFinal PSNR: %.4f (dB)", mse, psnr));
- }
+ reportStatus("Unique vector codebook, MSE: %f PSNR: %f(dB)", mse, psnr);
return new LBGResult(vectorDimensions, codebook, frequencies, mse, psnr);
}
@@ -103,40 +115,23 @@ public class LBGVectorQuantizer {
* @return Result of the search.
*/
public LBGResult findOptimalCodebook() {
- return findOptimalCodebook(false);
- }
-
-
- /**
- * Find the optimal codebook of vectors, used for vector quantization.
- *
- * @param isVerbose True if program algorithm should be verbose.
- * @return Result of the search.
- */
- public LBGResult findOptimalCodebook(boolean isVerbose) {
- Stopwatch stopwatch = Stopwatch.startNew("findOptimalCodebook");
- this.verbose = isVerbose;
+ Stopwatch stopwatch = Stopwatch.startNew("LBG::findOptimalCodebook()");
if (uniqueVectorCount < codebookSize) {
return createCodebookFromUniqueVectors();
}
LearningCodebookEntry[] codebook = initializeCodebook();
- if (verbose) {
- System.out.println("Got initial codebook. Improving codebook...");
- }
+ reportStatus("LBG::findOptimalCodebook() - Got initial codebook. Improving it...");
+
LBG(codebook, EPSILON * 0.1);
final double finalMse = averageMse(codebook);
final double psnr = Utils.calculatePsnr(finalMse, U16.Max);
- if (verbose) {
- System.out.println(String.format("Improved codebook, final average MSE: %.4f PSNR: %.4f (dB)",
- finalMse,
- psnr));
- }
+ reportStatus("LBG::findOptimalCodebook() - Improved the codebook. Final MSE: %f PSNR: %f (dB)",
+ finalMse,
+ psnr);
stopwatch.stop();
- if (verbose) {
- System.out.println(stopwatch);
- }
+ reportStatus(stopwatch.toString());
return new LBGResult(vectorDimensions, learningCodebookToCodebook(codebook), frequencies, finalMse, psnr);
}
@@ -384,22 +379,17 @@ public class LBGVectorQuantizer {
}
codebook = newCodebook;
assert (codebook.length == (currentCodebookSize * 2));
- if (verbose) {
- System.out.println(String.format("Split from %d -> %d", currentCodebookSize, currentCodebookSize * 2));
- }
+ reportStatus("LBG::initializeCodebook() - Dividing codebook from %d --> %d",
+ currentCodebookSize,
+ 2 * currentCodebookSize);
currentCodebookSize *= 2;
// Execute LBG Algorithm on current codebook to improve it.
- if (verbose) {
- System.out.println("Improving current codebook...");
- }
LBG(codebook);
final double avgMse = averageMse(codebook);
- if (verbose) {
- System.out.println(String.format("Average MSE: %.4f", avgMse));
- }
+ reportStatus("MSE of improved divided codebook: %f", avgMse);
}
return codebook;
}
@@ -463,32 +453,26 @@ public class LBGVectorQuantizer {
avgDistortion /= codebook.length;
// Calculate distortion
- double dist = (previousDistortion - avgDistortion) / avgDistortion;
- if (verbose) {
- System.out.println(String.format("---- It: %d Distortion: %.5f", iteration++, dist));
- System.out.println(String.format("Last Dist: %.5f Current dist: %.5f", lastDist, dist));
- }
+ double distortion = (previousDistortion - avgDistortion) / avgDistortion;
+ reportStatus("LBG::LBG() - Iteration: %d Distortion: %.5f", iteration++, distortion);
- if (Double.isNaN(dist)) {
- if (verbose) {
- System.out.println("Distortion is NaN.");
- }
+
+ if (Double.isNaN(distortion)) {
+ reportStatus("Distortion is NaN. Stopping LBG::LBG().");
break;
}
- if (dist > lastDist) {
- if (verbose) {
- System.out.println("Previous distortion was better. Ending LBG...");
- }
+ if (distortion > lastDist) {
+ reportStatus("Previous distortion was better. Stopping LBG::LBG().");
break;
}
// Check distortion against epsilon
- if (dist < epsilon) {
+ if (distortion < epsilon) {
break;
} else {
previousDistortion = avgDistortion;
- lastDist = dist;
+ lastDist = distortion;
}
}
}
@@ -665,7 +649,6 @@ public class LBGVectorQuantizer {
*/
private void calculateEntryProperties(LearningCodebookEntry[] codebook) {
- Stopwatch stopwatch = Stopwatch.startNew("calculateEntryProperties");
int value;
EntryInfo[] entryInfos = new EntryInfo[codebook.length];
for (int i = 0; i < entryInfos.length; i++) {
@@ -695,10 +678,6 @@ public class LBGVectorQuantizer {
for (int i = 0; i < codebook.length; i++) {
codebook[i].setInfo(entryInfos[i]);
}
- stopwatch.stop();
- if (this.verbose) {
- System.out.println(stopwatch);
- }
}