diff --git a/src/main/java/cz/it4i/qcmp/cli/functions/DebugFunction.java b/src/main/java/cz/it4i/qcmp/cli/functions/DebugFunction.java
index 32b62054975fec4337112abca419f3befb641b95..e2b59ee7e7d004c5ed20a2c2b82fde70914aca76 100644
--- a/src/main/java/cz/it4i/qcmp/cli/functions/DebugFunction.java
+++ b/src/main/java/cz/it4i/qcmp/cli/functions/DebugFunction.java
@@ -1,19 +1,7 @@
 package cz.it4i.qcmp.cli.functions;
 
-import cz.it4i.qcmp.cache.QuantizationCacheManager;
-import cz.it4i.qcmp.cache.VqQvcFile;
 import cz.it4i.qcmp.cli.CompressionOptionsCLIParser;
 import cz.it4i.qcmp.cli.CustomFunctionBase;
-import cz.it4i.qcmp.huffman.HuffmanNode;
-import cz.it4i.qcmp.huffman.HuffmanTreeBuilder;
-import cz.it4i.qcmp.io.InBitStream;
-import cz.it4i.qcmp.io.OutBitStream;
-import cz.it4i.qcmp.quantization.vector.VQCodebook;
-import cz.it4i.qcmp.utilities.Utils;
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
 
 @SuppressWarnings("ConstantConditions")
 public class DebugFunction extends CustomFunctionBase {
@@ -29,38 +17,37 @@ public class DebugFunction extends CustomFunctionBase {
     @Override
     public boolean run() {
 
-        final VQCodebook codebook = ((VqQvcFile) QuantizationCacheManager.readCacheFile("D:\\tmp\\codebook.qvc")).getCodebook();
-
-        final int[] symbols = new int[codebook.getCodebookSize()];
-        for (int i = 0; i < codebook.getCodebookSize(); i++) {
-            symbols[i] = i;
-        }
-
-        final HuffmanTreeBuilder huffmanBuilder = new HuffmanTreeBuilder(symbols, codebook.getVectorFrequencies());
-        huffmanBuilder.buildHuffmanTree();
-
-        final int bitsPerSymbol = (int) Utils.log2(codebook.getCodebookSize());
-        try (final OutBitStream bitStream = new OutBitStream(new FileOutputStream("D:\\tmp\\huffman_tree.data", false),
-                                                             bitsPerSymbol,
-                                                             64)) {
-            huffmanBuilder.createEncoder().getRoot().writeToBinaryStream(bitStream);
-        } catch (final IOException e) {
-            e.printStackTrace();
-        }
-
-
-        HuffmanNode readRoot = null;
-        try (final InBitStream inBitStream = new InBitStream(new FileInputStream("D:\\tmp\\huffman_tree.data"), bitsPerSymbol, 256)) {
-            readRoot = HuffmanNode.readFromStream(inBitStream);
-        } catch (final IOException ex) {
-            ex.printStackTrace();
-        }
-
-        readRoot.
-
-        final boolean equal = huffmanBuilder.createEncoder().getRoot().treeEqual(readRoot);
-
-        System.out.println(readRoot != null);
+        //        final VQCodebook codebook = ((VqQvcFile) QuantizationCacheManager.readCacheFile("D:\\tmp\\codebook.qvc")).getCodebook();
+        //
+        //        final int[] symbols = new int[codebook.getCodebookSize()];
+        //        for (int i = 0; i < codebook.getCodebookSize(); i++) {
+        //            symbols[i] = i;
+        //        }
+        //
+        //        final HuffmanTreeBuilder huffmanBuilder = new HuffmanTreeBuilder(symbols, codebook.getVectorFrequencies());
+        //        huffmanBuilder.buildHuffmanTree();
+        //
+        //        final int bitsPerSymbol = (int) Utils.log2(codebook.getCodebookSize());
+        //        try (final OutBitStream bitStream = new OutBitStream(new FileOutputStream("D:\\tmp\\huffman_tree.data", false),
+        //                                                             bitsPerSymbol,
+        //                                                             64)) {
+        //            huffmanBuilder.createEncoder().getRoot().writeToBinaryStream(bitStream);
+        //        } catch (final IOException e) {
+        //            e.printStackTrace();
+        //        }
+        //
+        //
+        //        HuffmanNode readRoot = null;
+        //        try (final InBitStream inBitStream = new InBitStream(new FileInputStream("D:\\tmp\\huffman_tree.data"), bitsPerSymbol,
+        //        256)) {
+        //            readRoot = HuffmanNode.readFromStream(inBitStream);
+        //        } catch (final IOException ex) {
+        //            ex.printStackTrace();
+        //        }
+        //
+        //        final boolean equal = huffmanBuilder.createEncoder().getRoot().treeEqual(readRoot);
+        //
+        //        System.out.println(readRoot != null);
 
         return true;
     }
diff --git a/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java b/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java
index f41106e7bbcc8eebf1ac90ceba9899272a4e7b8e..0278a0eec9ec3cd3e1cf1a58257d2e5f679e96e3 100644
--- a/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java
+++ b/src/main/java/cz/it4i/qcmp/compression/CompressorDecompressorBase.java
@@ -3,9 +3,7 @@ package cz.it4i.qcmp.compression;
 import cz.it4i.qcmp.compression.exception.ImageCompressionException;
 import cz.it4i.qcmp.compression.listeners.IProgressListener;
 import cz.it4i.qcmp.compression.listeners.IStatusListener;
-import cz.it4i.qcmp.huffman.HuffmanDecoder;
 import cz.it4i.qcmp.huffman.HuffmanEncoder;
-import cz.it4i.qcmp.huffman.HuffmanTreeBuilder;
 import cz.it4i.qcmp.io.InputData;
 import cz.it4i.qcmp.io.OutBitStream;
 
@@ -101,19 +99,7 @@ public abstract class CompressorDecompressorBase {
         }
         return symbols;
     }
-
-    protected HuffmanEncoder createHuffmanEncoder(final int[] symbols, final long[] frequencies) {
-        final HuffmanTreeBuilder huffman = new HuffmanTreeBuilder(symbols, frequencies);
-        huffman.buildHuffmanTree();
-        return huffman.createEncoder();
-    }
-
-    protected HuffmanDecoder createHuffmanDecoder(final int[] symbols, final long[] frequencies) {
-        final HuffmanTreeBuilder huffman = new HuffmanTreeBuilder(symbols, frequencies);
-        huffman.buildHuffmanTree();
-        return huffman.createDecoder();
-    }
-
+    
     protected int[] getPlaneIndicesForCompression(final InputData inputData) {
         if (inputData.isPlaneIndexSet()) {
             return new int[]{inputData.getPlaneIndex()};
diff --git a/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java b/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java
index b782dcc81cf57ed0680e3cc282151fea418e4209..effc516fc4262ec7e3d8ef13f0a0af87040829ce 100644
--- a/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java
+++ b/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java
@@ -45,8 +45,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
     public void preloadGlobalCodebook(final IQvcFile codebookCacheFile) {
         final SQCodebook cachedCodebook = ((SqQvcFile) codebookCacheFile).getCodebook();
         cachedQuantizer = new ScalarQuantizer(cachedCodebook);
-        cachedHuffmanEncoder = createHuffmanEncoder(createHuffmanSymbols(cachedCodebook.getCodebookSize()),
-                                                    cachedCodebook.getSymbolFrequencies());
+        cachedHuffmanEncoder = cachedCodebook.getHuffmanEncoder();
     }
 
     /**
@@ -89,8 +88,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
             trainAndSaveCodebook();
         }
 
-        final SQCodebook codebook = cacheManager.loadSQCodebook(options.getInputDataInfo().getCacheFileName(),
-                                                                getCodebookSize());
+        final SQCodebook codebook = cacheManager.loadSQCodebook(options.getInputDataInfo().getCacheFileName(), getCodebookSize());
         if (codebook == null) {
             throw new ImageCompressionException("Failed to read quantization values from cache file.");
         }
@@ -123,7 +121,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
             reportStatusToListeners("Loading codebook from cache file.");
 
             quantizer = loadQuantizerFromCache();
-            huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getCodebook().getSymbolFrequencies());
+            huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder();
 
             reportStatusToListeners("Cached quantizer with huffman coder created.");
             writeCodebookToOutputStream(quantizer, compressStream);
@@ -139,7 +137,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
 
             reportStatusToListeners(String.format("Training scalar quantizer from middle plane %d.", middlePlaneIndex));
             quantizer = trainScalarQuantizerFromData(middlePlaneData);
-            huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getCodebook().getSymbolFrequencies());
+            huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder();
 
             stopwatch.stop();
             writeCodebookToOutputStream(quantizer, compressStream);
@@ -175,7 +173,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
                 quantizer = trainScalarQuantizerFromData(planeData);
                 writeCodebookToOutputStream(quantizer, compressStream);
 
-                huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getCodebook().getSymbolFrequencies());
+                huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder();
             }
 
             assert (quantizer != null) : "Scalar Quantizer wasn't initialized.";
@@ -200,7 +198,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
         } catch (final Exception e) {
             throw new ImageCompressionException("Unable to create SCIFIO reader. " + e.getMessage());
         }
-        int[] trainData = null;
+        final int[] trainData;
 
         if (options.getCodebookType() == CompressionOptions.CodebookType.MiddlePlane) {
             final int middlePlaneIndex = getMiddlePlaneIndex();
diff --git a/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java b/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java
index 703beda0fe4ddf5f18f30f927a4b0bda395301ea..e3433a4d1a529e8173606ab57cbbac5cfe5fa802 100644
--- a/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java
+++ b/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java
@@ -5,6 +5,7 @@ import cz.it4i.qcmp.cache.SqQvcFile;
 import cz.it4i.qcmp.compression.exception.ImageDecompressionException;
 import cz.it4i.qcmp.fileformat.QCMPFileHeader;
 import cz.it4i.qcmp.huffman.HuffmanDecoder;
+import cz.it4i.qcmp.huffman.HuffmanTreeBuilder;
 import cz.it4i.qcmp.io.InBitStream;
 import cz.it4i.qcmp.quantization.scalar.SQCodebook;
 import cz.it4i.qcmp.utilities.Stopwatch;
@@ -22,8 +23,7 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
         super(options);
     }
 
-    private SQCodebook readScalarQuantizationValues(final DataInputStream compressedStream,
-                                                    final int codebookSize) throws ImageDecompressionException {
+    private SQCodebook readSqCodebook(final DataInputStream compressedStream, final int codebookSize) throws ImageDecompressionException {
         final int[] quantizationValues = new int[codebookSize];
         final long[] symbolFrequencies = new long[codebookSize];
         try {
@@ -36,7 +36,9 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
         } catch (final IOException ioEx) {
             throw new ImageDecompressionException("Unable to read quantization values from compressed stream.", ioEx);
         }
-        return new SQCodebook(quantizationValues, symbolFrequencies);
+        final HuffmanTreeBuilder builder = new HuffmanTreeBuilder(createHuffmanSymbols(codebookSize), symbolFrequencies);
+        builder.buildHuffmanTree();
+        return new SQCodebook(quantizationValues, builder.getRoot());
     }
 
     @Override
@@ -45,7 +47,6 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
                            final QCMPFileHeader header) throws ImageDecompressionException {
 
         final int codebookSize = (int) Math.pow(2, header.getBitsPerCodebookIndex());
-        final int[] huffmanSymbols = createHuffmanSymbols(codebookSize);
         final int planeCountForDecompression = header.getImageSizeZ();
 
         final int planePixelCount = header.getImageSizeX() * header.getImageSizeY();
@@ -55,8 +56,8 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
         if (!header.isCodebookPerPlane()) {
             // There is only one codebook.
             reportStatusToListeners("Loading single codebook and huffman coder.");
-            codebook = readScalarQuantizationValues(compressedStream, codebookSize);
-            huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getSymbolFrequencies());
+            codebook = readSqCodebook(compressedStream, codebookSize);
+            huffmanDecoder = codebook.getHuffmanDecoder();
         }
 
         final Stopwatch stopwatch = new Stopwatch();
@@ -64,8 +65,8 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
             stopwatch.restart();
             if (header.isCodebookPerPlane()) {
                 reportStatusToListeners("Loading plane codebook...");
-                codebook = readScalarQuantizationValues(compressedStream, codebookSize);
-                huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getSymbolFrequencies());
+                codebook = readSqCodebook(compressedStream, codebookSize);
+                huffmanDecoder = codebook.getHuffmanDecoder();
             }
             assert (codebook != null && huffmanDecoder != null);
 
@@ -110,8 +111,7 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
         final SqQvcFile codebookCache = (SqQvcFile) codebookCacheFile;
 
         cachedCodebook = codebookCache.getCodebook();
-        cachedHuffmanDecoder = createHuffmanDecoder(createHuffmanSymbols(cachedCodebook.getCodebookSize()),
-                                                    cachedCodebook.getSymbolFrequencies());
+        cachedHuffmanDecoder = cachedCodebook.getHuffmanDecoder();
     }
 
     @Override
@@ -119,7 +119,6 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
                                    final short[][] buffer,
                                    final QCMPFileHeader header) throws ImageDecompressionException {
         final int codebookSize = (int) Math.pow(2, header.getBitsPerCodebookIndex());
-        final int[] huffmanSymbols = createHuffmanSymbols(codebookSize);
         final int planeCountForDecompression = header.getImageSizeZ();
 
         final int planePixelCount = header.getImageSizeX() * header.getImageSizeY();
@@ -128,15 +127,15 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
         HuffmanDecoder huffmanDecoder = null;
         if (!header.isCodebookPerPlane()) {
             // There is only one codebook.
-            codebook = readScalarQuantizationValues(compressedStream, codebookSize);
-            huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getSymbolFrequencies());
+            codebook = readSqCodebook(compressedStream, codebookSize);
+            huffmanDecoder = codebook.getHuffmanDecoder();
         }
 
         for (int planeIndex = 0; planeIndex < planeCountForDecompression; planeIndex++) {
             reportProgressToListeners(planeIndex, planeCountForDecompression, "Decompressing plane %d", planeIndex);
             if (header.isCodebookPerPlane()) {
-                codebook = readScalarQuantizationValues(compressedStream, codebookSize);
-                huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getSymbolFrequencies());
+                codebook = readSqCodebook(compressedStream, codebookSize);
+                huffmanDecoder = codebook.getHuffmanDecoder();
             }
             assert (codebook != null && huffmanDecoder != null);
 
diff --git a/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java b/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java
index babbf166675a3995e480c4271c5bf1b6d9c1a86c..b273f83c9d606fc00b09b54048cae6e1f7cf7058 100644
--- a/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java
+++ b/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java
@@ -16,7 +16,6 @@ import cz.it4i.qcmp.quantization.vector.VQCodebook;
 import cz.it4i.qcmp.quantization.vector.VectorQuantizer;
 import cz.it4i.qcmp.utilities.Stopwatch;
 import cz.it4i.qcmp.utilities.Utils;
-import org.jetbrains.annotations.NotNull;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -36,8 +35,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
     public void preloadGlobalCodebook(final IQvcFile codebookCacheFile) {
         final VQCodebook cachedCodebook = ((VqQvcFile) codebookCacheFile).getCodebook();
         cachedQuantizer = new VectorQuantizer(cachedCodebook);
-        cachedHuffmanEncoder = createHuffmanEncoder(createHuffmanSymbols(cachedCodebook.getCodebookSize()),
-                                                    cachedCodebook.getVectorFrequencies());
+        cachedHuffmanEncoder = cachedCodebook.getHuffmanEncoder();
     }
 
     public boolean shouldUseKdTree() {
@@ -74,6 +72,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
      */
     private void writeQuantizerToCompressStream(final VectorQuantizer quantizer,
                                                 final DataOutputStream compressStream) throws ImageCompressionException {
+        // TODO
         final int[][] codebook = quantizer.getCodebookVectors();
         try {
             for (final int[] entry : codebook) {
@@ -143,7 +142,6 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
         return compress1D2DVectors(compressStream, true, inputData);
     }
 
-    @NotNull
     private long[] compress1D2DVectors(final DataOutputStream compressStream,
                                        final boolean streamMode,
                                        final InputData inputData) throws ImageCompressionException {
@@ -166,7 +164,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
             if (options.getCodebookType() == CompressionOptions.CodebookType.Global) {
                 reportStatusToListeners("Loading codebook from cache file.");
                 quantizer = loadQuantizerFromCache();
-                huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getFrequencies());
+                huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder();
                 reportStatusToListeners("Cached quantizer with huffman coder created.");
                 writeQuantizerToCompressStream(quantizer, compressStream);
             } else if (options.getCodebookType() == CompressionOptions.CodebookType.MiddlePlane) {
@@ -175,7 +173,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
                 final int[][] refPlaneVectors = planeLoader.loadVectorsFromPlaneRange(0, options,
                                                                                       Utils.singlePlaneRange(getMiddlePlaneIndex()));
                 quantizer = trainVectorQuantizerFromPlaneVectors(refPlaneVectors);
-                huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getFrequencies());
+                huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder();
                 stopwatch.stop();
                 reportStatusToListeners("Middle plane codebook created in: " + stopwatch.getElapsedTimeString());
                 writeQuantizerToCompressStream(quantizer, compressStream);
@@ -209,7 +207,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
             if (!streamMode && !hasGeneralQuantizer) {
                 reportStatusToListeners(String.format("Training vector quantizer from plane %d.", planeIndex));
                 quantizer = trainVectorQuantizerFromPlaneVectors(planeVectors);
-                huffmanEncoder = createHuffmanEncoder(huffmanSymbols, quantizer.getFrequencies());
+                huffmanEncoder = quantizer.getCodebook().getHuffmanEncoder();
                 writeQuantizerToCompressStream(quantizer, compressStream);
             }
 
@@ -258,7 +256,6 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
                                  final InputData inputData) throws ImageCompressionException {
         assert (options.getCodebookType() == CompressionOptions.CodebookType.Global);
         final IPlaneLoader planeLoader;
-        final int[] huffmanSymbols = createHuffmanSymbols(getCodebookSize());
         try {
             planeLoader = PlaneLoaderFactory.getPlaneLoaderForInputFile(inputData);
             planeLoader.setWorkerCount(options.getWorkerCount());
@@ -286,7 +283,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
         final VectorQuantizer quantizer = (cachedQuantizer != null) ? cachedQuantizer : loadQuantizerFromCache();
         final HuffmanEncoder huffmanEncoder = (cachedHuffmanEncoder != null)
                 ? cachedHuffmanEncoder
-                : createHuffmanEncoder(huffmanSymbols, quantizer.getFrequencies());
+                : quantizer.getCodebook().getHuffmanEncoder();
         if (!streamMode)
             writeQuantizerToCompressStream(quantizer, compressStream);
 
@@ -387,8 +384,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
 
         codebookTrainer.findOptimalCodebook(vqCodebook -> {
             try {
-                assert ((vqCodebook.getCodebookSize() == vqCodebook.getVectors().length) &&
-                        (vqCodebook.getCodebookSize() == vqCodebook.getVectorFrequencies().length))
+                assert (vqCodebook.getCodebookSize() == vqCodebook.getVectors().length)
                         : "Codebook size, Vector count, Frequencies count mismatch";
                 qcm.saveCodebook(options.getInputDataInfo().getCacheFileName(), vqCodebook);
             } catch (final IOException e) {
diff --git a/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java b/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java
index 9262328746cf2fbec3d6cf5bbcd85edaccfa1871..65af70fe3057f6ee6ddce0c808e0b5528aaf8ce4 100644
--- a/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java
+++ b/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java
@@ -7,6 +7,7 @@ import cz.it4i.qcmp.data.*;
 import cz.it4i.qcmp.fileformat.QCMPFileHeader;
 import cz.it4i.qcmp.fileformat.QuantizationType;
 import cz.it4i.qcmp.huffman.HuffmanDecoder;
+import cz.it4i.qcmp.huffman.HuffmanTreeBuilder;
 import cz.it4i.qcmp.io.InBitStream;
 import cz.it4i.qcmp.quantization.vector.VQCodebook;
 import cz.it4i.qcmp.utilities.Stopwatch;
@@ -36,8 +37,8 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I
     }
 
     private long calculatePlaneVectorCount(final QCMPFileHeader header) {
-        final int vectorXCount = (int) Math.ceil((double) header.getImageSizeX() / (double) header.getVectorSizeX());
-        final int vectorYCount = (int) Math.ceil((double) header.getImageSizeY() / (double) header.getVectorSizeY());
+        final long vectorXCount = (long) Math.ceil((double) header.getImageSizeX() / (double) header.getVectorSizeX());
+        final long vectorYCount = (long) Math.ceil((double) header.getImageSizeY() / (double) header.getVectorSizeY());
         // Number of vectors per plane.
         return (vectorXCount * vectorYCount);
     }
@@ -62,8 +63,11 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I
             throw new ImageDecompressionException("Unable to read quantization values from compressed stream.", ioEx);
         }
 
+        final HuffmanTreeBuilder builder = new HuffmanTreeBuilder(createHuffmanSymbols(codebookSize), frequencies);
+        builder.buildHuffmanTree();
+
         // We don't care about vector dimensions in here.
-        return new VQCodebook(new V3i(0), codebookVectors, frequencies);
+        return new VQCodebook(new V3i(0), codebookVectors, builder.getRoot());
     }
 
     @Override
@@ -72,8 +76,7 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I
         final VqQvcFile codebookCache = (VqQvcFile) codebookCacheFile;
 
         cachedCodebook = codebookCache.getCodebook();
-        cachedHuffmanDecoder = createHuffmanDecoder(createHuffmanSymbols(cachedCodebook.getCodebookSize()),
-                                                    cachedCodebook.getVectorFrequencies());
+        cachedHuffmanDecoder = cachedCodebook.getHuffmanDecoder();
     }
 
 
@@ -118,21 +121,19 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I
         final int planeCountForDecompression = header.getImageSizeZ();
         final long planeVectorCount = calculatePlaneVectorCount(header);
         final V2i qVector = new V2i(header.getVectorSizeX(), header.getVectorSizeY());
-        final int[] huffmanSymbols = createHuffmanSymbols(codebookSize);
-
 
         VQCodebook codebook = null;
         HuffmanDecoder huffmanDecoder = null;
         if (!header.isCodebookPerPlane()) {
             // There is only one codebook.
             codebook = readCodebook(compressedStream, codebookSize, vectorSize);
-            huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getVectorFrequencies());
+            huffmanDecoder = codebook.getHuffmanDecoder();
         }
 
         for (int planeIndex = 0; planeIndex < planeCountForDecompression; planeIndex++) {
             if (header.isCodebookPerPlane()) {
                 codebook = readCodebook(compressedStream, codebookSize, vectorSize);
-                huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getVectorFrequencies());
+                huffmanDecoder = codebook.getHuffmanDecoder();
             }
             assert (codebook != null && huffmanDecoder != null);
 
@@ -239,7 +240,7 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I
 
 
         final VQCodebook codebook = readCodebook(compressedStream, codebookSize, vectorSize);
-        final HuffmanDecoder huffmanDecoder = createHuffmanDecoder(huffmanSymbols, codebook.getVectorFrequencies());
+        final HuffmanDecoder huffmanDecoder = codebook.getHuffmanDecoder();
 
         final int voxelLayerCount = VQImageCompressor.calculateVoxelLayerCount(header.getImageSizeZ(), header.getVectorSizeZ());
         final Stopwatch stopwatch = new Stopwatch();
diff --git a/src/main/java/cz/it4i/qcmp/quantization/scalar/LloydMaxU16ScalarQuantization.java b/src/main/java/cz/it4i/qcmp/quantization/scalar/LloydMaxU16ScalarQuantization.java
index 0dc3f31dfff51768f2eec7a8ce1e99d634c39f92..18915031145478bcd74d2514ba0aee662abb68b1 100644
--- a/src/main/java/cz/it4i/qcmp/quantization/scalar/LloydMaxU16ScalarQuantization.java
+++ b/src/main/java/cz/it4i/qcmp/quantization/scalar/LloydMaxU16ScalarQuantization.java
@@ -2,6 +2,7 @@ package cz.it4i.qcmp.quantization.scalar;
 
 import cz.it4i.qcmp.U16;
 import cz.it4i.qcmp.compression.listeners.IStatusListener;
+import cz.it4i.qcmp.huffman.HuffmanTreeBuilder;
 import cz.it4i.qcmp.quantization.QTrainIteration;
 import cz.it4i.qcmp.utilities.MinMaxResult;
 import cz.it4i.qcmp.utilities.Stopwatch;
@@ -258,7 +259,9 @@ public class LloydMaxU16ScalarQuantization {
     }
 
     public SQCodebook getCodebook() {
-        return new SQCodebook(centroids, frequencies);
+        final HuffmanTreeBuilder builder = new HuffmanTreeBuilder(codebookSize, frequencies);
+        builder.buildHuffmanTree();
+        return new SQCodebook(centroids, builder.getRoot());
     }
 }
 
diff --git a/src/main/java/cz/it4i/qcmp/quantization/vector/LBGResult.java b/src/main/java/cz/it4i/qcmp/quantization/vector/LBGResult.java
index 2bb63affb7f42f6161eed7a94af3dea96db241dd..4d0156e888244bd7e028fef9030c8782298b0cf2 100644
--- a/src/main/java/cz/it4i/qcmp/quantization/vector/LBGResult.java
+++ b/src/main/java/cz/it4i/qcmp/quantization/vector/LBGResult.java
@@ -1,6 +1,7 @@
 package cz.it4i.qcmp.quantization.vector;
 
 import cz.it4i.qcmp.data.V3i;
+import cz.it4i.qcmp.huffman.HuffmanTreeBuilder;
 
 public class LBGResult {
 
@@ -23,7 +24,9 @@ public class LBGResult {
     }
 
     public VQCodebook getCodebook() {
-        return new VQCodebook(vectorDims, codebookVectors, frequencies);
+        final HuffmanTreeBuilder builder = new HuffmanTreeBuilder(codebookVectors.length, frequencies);
+        builder.buildHuffmanTree();
+        return new VQCodebook(vectorDims, codebookVectors, builder.getRoot());
     }
 
     public double getAverageMse() {
diff --git a/src/main/java/cz/it4i/qcmp/quantization/vector/LBGVectorQuantizer.java b/src/main/java/cz/it4i/qcmp/quantization/vector/LBGVectorQuantizer.java
index 86d93dc147286d4dabb962ce1a020518a2c5540f..4f3aa5f81db4c482b3451f90e4ede7856ff7e67e 100644
--- a/src/main/java/cz/it4i/qcmp/quantization/vector/LBGVectorQuantizer.java
+++ b/src/main/java/cz/it4i/qcmp/quantization/vector/LBGVectorQuantizer.java
@@ -3,6 +3,7 @@ package cz.it4i.qcmp.quantization.vector;
 import cz.it4i.qcmp.U16;
 import cz.it4i.qcmp.compression.listeners.IStatusListener;
 import cz.it4i.qcmp.data.V3i;
+import cz.it4i.qcmp.huffman.HuffmanTreeBuilder;
 import cz.it4i.qcmp.utilities.Stopwatch;
 import cz.it4i.qcmp.utilities.Utils;
 
@@ -207,9 +208,7 @@ public class LBGVectorQuantizer {
 
                 workers[wId] = new Thread(() -> {
                     final long[] workerFrequencies = new long[codebook.length];
-                    final VectorQuantizer quantizer = new VectorQuantizer(new VQCodebook(vectorDimensions,
-                                                                                         codebook,
-                                                                                         frequencies));
+                    final VectorQuantizer quantizer = new VectorQuantizer(new VQCodebook(vectorDimensions, codebook, null));
 
                     double threadMse = 0.0;
                     int[] vector;
@@ -245,9 +244,7 @@ public class LBGVectorQuantizer {
             }
             mse = _mse / (double) workerCount;
         } else {
-            final VectorQuantizer quantizer = new VectorQuantizer(new VQCodebook(vectorDimensions,
-                                                                                 codebook,
-                                                                                 frequencies));
+            final VectorQuantizer quantizer = new VectorQuantizer(new VQCodebook(vectorDimensions, codebook, null));
             int qIndex;
             int[] qVector;
             for (final TrainingVector trV : trainingVectors) {
@@ -412,9 +409,10 @@ public class LBGVectorQuantizer {
                 final long[] codebookFrequencies = new long[codebook.length];
                 System.arraycopy(frequencies, 0, codebookFrequencies, 0, codebook.length);
 
-                codebookFoundCallback.process(new VQCodebook(vectorDimensions,
-                                                             learningCodebookToCodebook(codebook),
-                                                             codebookFrequencies));
+
+                final HuffmanTreeBuilder builder = new HuffmanTreeBuilder(codebook.length, frequencies);
+                builder.buildHuffmanTree();
+                codebookFoundCallback.process(new VQCodebook(vectorDimensions, learningCodebookToCodebook(codebook), builder.getRoot()));
             }
         }
         return codebook;
diff --git a/src/main/java/cz/it4i/qcmp/quantization/vector/VQCodebook.java b/src/main/java/cz/it4i/qcmp/quantization/vector/VQCodebook.java
index a47f71c411b6e0a2f6c8148e60ce75f6c177976b..cc618cf898a0993a2ec78c281315d61be9257e02 100644
--- a/src/main/java/cz/it4i/qcmp/quantization/vector/VQCodebook.java
+++ b/src/main/java/cz/it4i/qcmp/quantization/vector/VQCodebook.java
@@ -32,6 +32,7 @@ public class VQCodebook extends Codebook {
      * @param huffmanRoot Root of the huffman tree.
      */
     public VQCodebook(final V3i vectorDims, final int[][] vectors, final HuffmanNode huffmanRoot) {
+        super(huffmanRoot);
         this.vectorDims = vectorDims;
         this.vectors = vectors;
         this.codebookSize = vectors.length;
diff --git a/src/main/java/cz/it4i/qcmp/quantization/vector/VectorQuantizer.java b/src/main/java/cz/it4i/qcmp/quantization/vector/VectorQuantizer.java
index fe7341497d35bec39130d8e3da998f8167b3f62f..639d7eec024bc021747eb79ef3ec9fdc8de5d0b9 100644
--- a/src/main/java/cz/it4i/qcmp/quantization/vector/VectorQuantizer.java
+++ b/src/main/java/cz/it4i/qcmp/quantization/vector/VectorQuantizer.java
@@ -11,16 +11,15 @@ public class VectorQuantizer {
     private final VectorDistanceMetric metric = VectorDistanceMetric.Euclidean;
     private final int[][] codebookVectors;
     private final int vectorSize;
-    private final long[] frequencies;
+    private final VQCodebook codebook;
 
-    //    private final KDTree kdTree;
+    // private final KDTree kdTree;
 
     public VectorQuantizer(final VQCodebook codebook) {
+        this.codebook = codebook;
         this.codebookVectors = codebook.getVectors();
         this.vectorSize = codebook.getVectors()[0].length;
-        this.frequencies = codebook.getVectorFrequencies();
-
-        //        kdTree = new KDTreeBuilder(this.vectorSize, 8).buildTree(codebook.getVectors());
+        // kdTree = new KDTreeBuilder(this.vectorSize, 8).buildTree(codebook.getVectors());
     }
 
     public int[] quantize(final int[] dataVector) {
@@ -167,8 +166,8 @@ public class VectorQuantizer {
         return codebookVectors;
     }
 
-    public long[] getFrequencies() {
-        return frequencies;
+    public VQCodebook getCodebook() {
+        return codebook;
     }
 }