Exemplo n.º 1
0
        /// <summary>
        /// Reindex the 24/32 BPP (A)RGB image to a 8BPP
        /// </summary>
        /// <returns>Bitmap</returns>
        public Bitmap SimpleReindex()
        {
            List <Color>             colors = new List <Color>();
            Dictionary <Color, byte> lookup = new Dictionary <Color, byte>();

            using (FastChunkyBitmap bbbDest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap)
            {
                bbbDest.Lock();
                using (IFastBitmap bbbSrc = FastBitmap.Create(sourceBitmap))
                {
                    IFastBitmapWithBlend bbbSrcBlend = bbbSrc as IFastBitmapWithBlend;

                    bbbSrc.Lock();
                    byte index;
                    for (int y = 0; y < bbbSrc.Height; y++)
                    {
                        for (int x = 0; x < bbbSrc.Width; x++)
                        {
                            Color color;
                            if (bbbSrcBlend != null)
                            {
                                color = bbbSrcBlend.GetBlendedColorAt(x, y);
                            }
                            else
                            {
                                color = bbbSrc.GetColorAt(x, y);
                            }
                            if (lookup.ContainsKey(color))
                            {
                                index = lookup[color];
                            }
                            else
                            {
                                colors.Add(color);
                                index = (byte)(colors.Count - 1);
                                lookup.Add(color, index);
                            }
                            bbbDest.SetColorIndexAt(x, y, index);
                        }
                    }
                }
            }

            // generates palette
            ColorPalette imagePalette = resultBitmap.Palette;

            Color[] entries = imagePalette.Entries;
            for (Int32 paletteIndex = 0; paletteIndex < 256; paletteIndex++)
            {
                if (paletteIndex < colorCount)
                {
                    entries[paletteIndex] = colors[paletteIndex];
                }
                else
                {
                    entries[paletteIndex] = Color.Black;
                }
            }
            resultBitmap.Palette = imagePalette;

            // Make sure the bitmap is not disposed, as we return it.
            Bitmap tmpBitmap = resultBitmap;

            resultBitmap = null;
            return(tmpBitmap);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Get the image
        /// </summary>
        public Bitmap GetQuantizedImage(int allowedColorCount)
        {
            if (allowedColorCount > 256)
            {
                throw new ArgumentOutOfRangeException("Quantizing muss be done to get less than 256 colors");
            }
            if (colorCount < allowedColorCount)
            {
                // Simple logic to reduce to 8 bit
                LOG.Info("Colors in the image are already less as whished for, using simple copy to indexed image, no quantizing needed!");
                return(SimpleReindex());
            }
            // preprocess the colors
            CalculateMoments();
            LOG.Info("Calculated the moments...");
            Int32 next = 0;

            Single[] volumeVariance = new Single[MAXCOLOR];

            // processes the cubes
            for (Int32 cubeIndex = 1; cubeIndex < allowedColorCount; ++cubeIndex)
            {
                // if cut is possible; make it
                if (Cut(cubes[next], cubes[cubeIndex]))
                {
                    volumeVariance[next]      = cubes[next].Volume > 1 ? CalculateVariance(cubes[next]) : 0.0f;
                    volumeVariance[cubeIndex] = cubes[cubeIndex].Volume > 1 ? CalculateVariance(cubes[cubeIndex]) : 0.0f;
                }
                else
                {
                    // the cut was not possible, revert the index
                    volumeVariance[next] = 0.0f;
                    cubeIndex--;
                }

                next = 0;
                Single temp = volumeVariance[0];

                for (Int32 index = 1; index <= cubeIndex; ++index)
                {
                    if (volumeVariance[index] > temp)
                    {
                        temp = volumeVariance[index];
                        next = index;
                    }
                }

                if (temp <= 0.0)
                {
                    allowedColorCount = cubeIndex + 1;
                    break;
                }
            }

            Int32[] lookupRed   = new Int32[MAXCOLOR];
            Int32[] lookupGreen = new Int32[MAXCOLOR];
            Int32[] lookupBlue  = new Int32[MAXCOLOR];

            tag = new byte[MAXVOLUME];

            // precalculates lookup tables
            for (int k = 0; k < allowedColorCount; ++k)
            {
                Mark(cubes[k], k, tag);

                long weight = Volume(cubes[k], weights);

                if (weight > 0)
                {
                    lookupRed[k]   = (int)(Volume(cubes[k], momentsRed) / weight);
                    lookupGreen[k] = (int)(Volume(cubes[k], momentsGreen) / weight);
                    lookupBlue[k]  = (int)(Volume(cubes[k], momentsBlue) / weight);
                }
                else
                {
                    lookupRed[k]   = 0;
                    lookupGreen[k] = 0;
                    lookupBlue[k]  = 0;
                }
            }

            reds   = new Int32[allowedColorCount + 1];
            greens = new Int32[allowedColorCount + 1];
            blues  = new Int32[allowedColorCount + 1];
            sums   = new Int32[allowedColorCount + 1];

            LOG.Info("Starting bitmap reconstruction...");

            using (FastChunkyBitmap dest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap)
            {
                using (IFastBitmap src = FastBitmap.Create(sourceBitmap))
                {
                    IFastBitmapWithBlend     srcBlend = src as IFastBitmapWithBlend;
                    Dictionary <Color, byte> lookup   = new Dictionary <Color, byte>();
                    byte bestMatch;
                    for (int y = 0; y < src.Height; y++)
                    {
                        for (int x = 0; x < src.Width; x++)
                        {
                            Color color;
                            if (srcBlend != null)
                            {
                                // WithoutAlpha, this makes it possible to ignore the alpha
                                color = srcBlend.GetBlendedColorAt(x, y);
                            }
                            else
                            {
                                color = src.GetColorAt(x, y);
                            }

                            // Check if we already matched the color
                            if (!lookup.ContainsKey(color))
                            {
                                // If not we need to find the best match

                                // First get initial match
                                bestMatch = dest.GetColorIndexAt(x, y);
                                bestMatch = tag[bestMatch];

                                Int32 bestDistance = 100000000;
                                for (int lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++)
                                {
                                    Int32 foundRed   = lookupRed[lookupIndex];
                                    Int32 foundGreen = lookupGreen[lookupIndex];
                                    Int32 foundBlue  = lookupBlue[lookupIndex];
                                    Int32 deltaRed   = color.R - foundRed;
                                    Int32 deltaGreen = color.G - foundGreen;
                                    Int32 deltaBlue  = color.B - foundBlue;

                                    Int32 distance = deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue;

                                    if (distance < bestDistance)
                                    {
                                        bestDistance = distance;
                                        bestMatch    = (byte)lookupIndex;
                                    }
                                }
                                lookup.Add(color, bestMatch);
                            }
                            else
                            {
                                // Already matched, so we just use the lookup
                                bestMatch = lookup[color];
                            }

                            reds[bestMatch]   += color.R;
                            greens[bestMatch] += color.G;
                            blues[bestMatch]  += color.B;
                            sums[bestMatch]++;

                            dest.SetColorIndexAt(x, y, bestMatch);
                        }
                    }
                }
            }

            // generates palette
            ColorPalette imagePalette = resultBitmap.Palette;

            Color[] entries = imagePalette.Entries;
            for (Int32 paletteIndex = 0; paletteIndex < allowedColorCount; paletteIndex++)
            {
                if (sums[paletteIndex] > 0)
                {
                    reds[paletteIndex]   /= sums[paletteIndex];
                    greens[paletteIndex] /= sums[paletteIndex];
                    blues[paletteIndex]  /= sums[paletteIndex];
                }

                entries[paletteIndex] = Color.FromArgb(255, reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]);
            }
            resultBitmap.Palette = imagePalette;

            // Make sure the bitmap is not disposed, as we return it.
            Bitmap tmpBitmap = resultBitmap;

            resultBitmap = null;
            return(tmpBitmap);
        }
Exemplo n.º 3
0
        /// <summary>
        /// See <see cref="IColorQuantizer.Prepare"/> for more details.
        /// </summary>
        public WuQuantizer(Bitmap sourceBitmap)
        {
            this.sourceBitmap = sourceBitmap;
            // Make sure the color count variables are reset
            BitArray bitArray = new BitArray((int)Math.Pow(2, 24));

            colorCount = 0;

            // creates all the cubes
            cubes = new WuColorCube[MAXCOLOR];

            // initializes all the cubes
            for (Int32 cubeIndex = 0; cubeIndex < MAXCOLOR; cubeIndex++)
            {
                cubes[cubeIndex] = new WuColorCube();
            }

            // resets the reference minimums
            cubes[0].RedMinimum   = 0;
            cubes[0].GreenMinimum = 0;
            cubes[0].BlueMinimum  = 0;

            // resets the reference maximums
            cubes[0].RedMaximum   = MAXSIDEINDEX;
            cubes[0].GreenMaximum = MAXSIDEINDEX;
            cubes[0].BlueMaximum  = MAXSIDEINDEX;

            weights      = new Int64[SIDESIZE, SIDESIZE, SIDESIZE];
            momentsRed   = new Int64[SIDESIZE, SIDESIZE, SIDESIZE];
            momentsGreen = new Int64[SIDESIZE, SIDESIZE, SIDESIZE];
            momentsBlue  = new Int64[SIDESIZE, SIDESIZE, SIDESIZE];
            moments      = new Single[SIDESIZE, SIDESIZE, SIDESIZE];

            Int32[] table = new Int32[256];

            for (Int32 tableIndex = 0; tableIndex < 256; ++tableIndex)
            {
                table[tableIndex] = tableIndex * tableIndex;
            }

            // Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage
            using (IFastBitmap sourceFastBitmap = FastBitmap.Create(sourceBitmap))
            {
                IFastBitmapWithBlend sourceFastBitmapWithBlend = sourceFastBitmap as IFastBitmapWithBlend;
                sourceFastBitmap.Lock();
                using (FastChunkyBitmap destinationFastBitmap = FastBitmap.CreateEmpty(sourceBitmap.Size, PixelFormat.Format8bppIndexed, Color.White) as FastChunkyBitmap)
                {
                    destinationFastBitmap.Lock();
                    for (int y = 0; y < sourceFastBitmap.Height; y++)
                    {
                        for (int x = 0; x < sourceFastBitmap.Width; x++)
                        {
                            Color color;
                            if (sourceFastBitmapWithBlend == null)
                            {
                                color = sourceFastBitmap.GetColorAt(x, y);
                            }
                            else
                            {
                                color = sourceFastBitmapWithBlend.GetBlendedColorAt(x, y);
                            }
                            // To count the colors
                            int index = color.ToArgb() & 0x00ffffff;
                            // Check if we already have this color
                            if (!bitArray.Get(index))
                            {
                                // If not, add 1 to the single colors
                                colorCount++;
                                bitArray.Set(index, true);
                            }

                            Int32 indexRed   = (color.R >> 3) + 1;
                            Int32 indexGreen = (color.G >> 3) + 1;
                            Int32 indexBlue  = (color.B >> 3) + 1;

                            weights[indexRed, indexGreen, indexBlue]++;
                            momentsRed[indexRed, indexGreen, indexBlue]   += color.R;
                            momentsGreen[indexRed, indexGreen, indexBlue] += color.G;
                            momentsBlue[indexRed, indexGreen, indexBlue]  += color.B;
                            moments[indexRed, indexGreen, indexBlue]      += table[color.R] + table[color.G] + table[color.B];

                            // Store the initial "match"
                            Int32 paletteIndex = (indexRed << 10) + (indexRed << 6) + indexRed + (indexGreen << 5) + indexGreen + indexBlue;
                            destinationFastBitmap.SetColorIndexAt(x, y, (byte)(paletteIndex & 0xff));
                        }
                    }
                    resultBitmap = destinationFastBitmap.UnlockAndReturnBitmap();
                }
            }
        }