/** Remove this child node, and make sure our parent absorbs our pixel statistics. */ void pruneChild() { --parent.nchild; parent.unique += unique; parent.total_red += total_red; parent.total_green += total_green; parent.total_blue += total_blue; parent.child[id] = null; --cube.nodes; cube = null; parent = null; }
/* * Procedure Classification begins by initializing a color * description tree of sufficient depth to represent each * possible input color in a leaf. However, it is impractical * to generate a fully-formed color description tree in the * classification phase for realistic values of cmax. If * colors components in the input image are quantized to k-bit * precision, so that cmax= 2k-1, the tree would need k levels * below the root node to allow representing each possible * input color in a leaf. This becomes prohibitive because the * tree's total number of nodes is 1 + sum(i=1,k,8k). * * A complete tree would require 19,173,961 nodes for k = 8, * cmax = 255. Therefore, to avoid building a fully populated * tree, QUANTIZE: (1) Initializes data structures for nodes * only as they are needed; (2) Chooses a maximum depth for * the tree as a function of the desired number of colors in * the output image (currently log2(colormap size)). * * For each pixel in the input image, classification scans * downward from the root of the color description tree. At * each level of the tree it identifies the single node which * represents a cube in RGB space containing It updates the * following data for each such node: * * number_pixels : Number of pixels whose color is contained * in the RGB cube which this node represents; * * unique : Number of pixels whose color is not represented * in a node at lower depth in the tree; initially, n2 = 0 * for all nodes except leaves of the tree. * * total_red/green/blue : Sums of the red, green, and blue * component values for all pixels not classified at a lower * depth. The combination of these sums and n2 will * ultimately characterize the mean color of a set of pixels * represented by this node. */ void classification() { int pixels[][] = this.pixels; int width = pixels.length; int height = pixels[0].length; // convert to indexed color for (int x = width; x-- > 0; ) { for (int y = height; y-- > 0; ) { int pixel = pixels[x][y]; int alpha = (pixel >> 24) & 0xFF; if (alpha != 255) { hasTrans = true; continue; // don't add transparent pixels to the cube } int red = (pixel >> 16) & 0xFF; int green = (pixel >> 8) & 0xFF; int blue = (pixel >> 0) & 0xFF; // a hard limit on the number of nodes in the tree if (nodes > MAX_NODES) { System.out.println("pruning"); root.pruneLevel(); --depth; } // walk the tree to depth, increasing the // number_pixels count for each node Node node = root; for (int level = 1; level <= depth; ++level) { int id = (((red > node.mid_red ? 1 : 0) << 0) | ((green > node.mid_green ? 1 : 0) << 1) | ((blue > node.mid_blue ? 1 : 0) << 2)); if (node.child[id] == null) { new Node(node, id, level); } node = node.child[id]; node.number_pixels += SHIFT[level]; } ++node.unique; node.total_red += red; node.total_green += green; node.total_blue += blue; } } // if we have transparent pixels, that cuts into the number // of other colors we can use. if (hasTrans) { this.max_colors--; } }