GR.Image.MemoryImage Assignment(CubeInfo cube_info, GR.Image.IImage pCD)
        {
            var format = GR.Drawing.PixelFormat.Format8bppIndexed;

            if (m_Colors <= 2)
            {
                format = GR.Drawing.PixelFormat.Format1bppIndexed;
            }

            /*
             * else if ( m_Colors <= 4 )
             * {
             * format = System.Drawing.Imaging.PixelFormat.Format2bppIndexed;
             * }*/
            else if (m_Colors <= 16)
            {
                format = GR.Drawing.PixelFormat.Format4bppIndexed;
            }

            var pImage = new GR.Image.MemoryImage(pCD.Width, pCD.Height, format);

            var pal = new RetroDevStudio.Palette(m_Colors);

            byte index;

            int count,
                i;

            NodeInfo node_info;

            uint dither,
                 id;


            // Allocate image colormap.
            cube_info.colormap = new PixelPacket[256];
            cube_info.colors   = 0;
            DefineColormap(cube_info, cube_info.root);

            // Create a reduced color image.
            dither = cube_info.quantize_info.dither;
            for (int y = 0; y < pCD.Height; y++)
            {
                //indexes=GetIndexes(image);
                for (int x = 0; x < pCD.Width; x += count)
                {
                    // Identify the deepest node containing the pixel's color.
                    count = 1;

                    uint pixel = pCD.GetPixel(x, y);
                    int  r     = (byte)((pixel & 0xff0000) >> 16),
                         g     = (byte)((pixel & 0xff00) >> 8),
                         b     = (byte)(pixel & 0xff);

                    node_info = cube_info.root;
                    for (index = MaxTreeDepth - 1; (int)index > 0; index--)
                    {
                        id = (uint)(((Downscale(r) >> index) & 0x01) << 2 |
                                    ((Downscale(g) >> index) & 0x01) << 1 |
                                    ((Downscale(b) >> index) & 0x01));
                        if ((node_info.census & (1 << (byte)id)) == 0)
                        {
                            break;
                        }
                        node_info = node_info.child[id];
                    }

                    // Find closest color among siblings and their children.
                    cube_info.color.red   = (byte)r;
                    cube_info.color.green = (byte)g;
                    cube_info.color.blue  = (byte)b;
                    cube_info.distance    = 3.0 * (MaxRGB() + 1) * (MaxRGB() + 1);
                    ClosestColor(cube_info, node_info.parent);
                    index = (byte)cube_info.color_number;
                    for (i = 0; i < count; i++)
                    {
                        if (cube_info.quantize_info.measure_error == 0)
                        {
                            pImage.SetPixel(x, y, index);
                        }
                    }
                }
            }

            for (i = 0; i < cube_info.colors; i++)
            {
                pal.ColorValues[i] = (uint)(0xff000000
                                            | (uint)(cube_info.colormap[i].red << 16)
                                            | (uint)(cube_info.colormap[i].green << 8)
                                            | (uint)cube_info.colormap[i].blue);

                pImage.SetPaletteColor(i, cube_info.colormap[i].red, cube_info.colormap[i].green, cube_info.colormap[i].blue);
            }


            return(pImage);
        }
        bool Classification(CubeInfo cube_info, GR.Image.IImage Image)
        {
            double bisect,
                   mid_red,
                   mid_green,
                   mid_blue;

            int count;

            NodeInfo node_info;

            double blue,
                   green,
                   red;

            uint index,
                 level,
                 id;


            for (int y = 0; y < Image.Height; ++y)
            {
                if (cube_info.nodes > MaxNodes)
                {
                    // Prune one level if the color tree is too large.
                    PruneLevel(cube_info, cube_info.root);
                    --cube_info.depth;
                }

                for (int x = 0; x < Image.Width; x += count)
                {
                    // Start at the root and descend the color cube tree.
                    count     = 1;
                    index     = MaxTreeDepth - 1;
                    bisect    = (MaxRGB() + 1) / 2.0;
                    mid_red   = MaxRGB() / 2.0;
                    mid_green = MaxRGB() / 2.0;
                    mid_blue  = MaxRGB() / 2.0;
                    node_info = cube_info.root;

                    uint pixel = Image.GetPixel(x, y);
                    int  r     = (int)((pixel & 0xff0000) >> 16);
                    int  g     = (int)((pixel & 0xff00) >> 8);
                    int  b     = (int)(pixel & 0xff);

                    for (level = 1; level <= cube_info.depth; level++)
                    {
                        bisect *= 0.5;
                        id      = (uint)(((Downscale(r) >> (byte)index) & 0x01) << 2 |
                                    ((Downscale(g) >> (byte)index) & 0x01) << 1 |
                                    ((Downscale(b) >> (byte)index) & 0x01));
                        mid_red   += (id & 4) != 0 ? bisect : -bisect;
                        mid_green += (id & 2) != 0 ? bisect : -bisect;
                        mid_blue  += (id & 1) != 0 ? bisect : -bisect;
                        if (node_info.child[id] == null)
                        {
                            // Set colors of new node to contain pixel.
                            node_info.census   |= (byte)(1 << (byte)id);
                            node_info.child[id] = GetNodeInfo(cube_info, (byte)id, (byte)level, node_info);
                            if (node_info.child[id] == null)
                            {
                                Debug.Log("this should never happen!");
                            }
                            if (level == cube_info.depth)
                            {
                                ++cube_info.colors;
                            }
                        }

                        // Approximate the quantization error represented by this node.
                        node_info = node_info.child[id];
                        red       = (double)r - mid_red;
                        green     = (double)g - mid_green;
                        blue      = (double)b - mid_blue;
                        node_info.quantize_error      += count * red * red + count * green * green + count * blue * blue;
                        cube_info.root.quantize_error += node_info.quantize_error;
                        --index;
                    }

                    // Sum RGB for this leaf for later derivation of the mean cube color.
                    node_info.number_unique += count;
                    node_info.total_red     += count * r;
                    node_info.total_green   += count * g;
                    node_info.total_blue    += count * b;
                }
            }
            return(true);
        }