OctreePalette::OctreePalette(const std::vector<RGBAPixel>& colors) : colors(colors) { // add each color to the octree, assign a palette index and update parents for (size_t i = 0; i < colors.size(); i++) { RGBAPixel color = colors[i]; Octree* node = Octree::findOrCreateNode(&octree, color); node->setColor(color); node->setColorID(i); node->updateParents(); } }
/** * Simple octree color quantization: Similar to http://rosettacode.org/wiki/Color_quantization#C */ void octreeColorQuantize(const RGBAImage& image, size_t max_colors, std::vector<RGBAPixel>& colors, Octree** octree) { assert(max_colors > 0); // have an octree with the colors as leaves Octree* internal_octree = new Octree(); // and a priority queue of leaves to be processed // the order of leaves is very important, see NodeComparator std::priority_queue<Octree*, std::vector<Octree*>, NodeComparator> queue; // insert the colors into the octree for (int x = 0; x < image.getWidth(); x++) { for (int y = 0; y < image.getHeight(); y++) { RGBAPixel color = image.pixel(x, y); Octree* node = Octree::findOrCreateNode(internal_octree, color); node->setColor(color); // add the leaf only once to the queue if (node->getCount() == 1) queue.push(node); } } // now: reduce the leaves until we have less colors than maximum while (queue.size() > max_colors) { Octree* node = queue.top(); assert(node->isLeaf()); queue.pop(); // add the color value of the leaf to the parent node->reduceToParent(); Octree* parent = node->getParent(); // delete the leaf (leaf is automatically removed from parent in reduceToParent()) delete node; // add parent to queue if it is a leaf now if (parent->isLeaf()) queue.push(parent); } // gather the quantized colors while (queue.size()) { Octree* node = queue.top(); assert(node->isLeaf()); node->setColorID(colors.size()); colors.push_back(node->getColor()); queue.pop(); } if (octree != nullptr) *octree = internal_octree; else delete internal_octree; }