java - Quantizzazione del colore gif/immagine efficace?




algorithm animated-gif (2)

Qui ... ho scritto questo e funziona un po 'più velocemente di Octree e sembra produrre risultati migliori sulla maggior parte delle immagini (ed è stato molto più facile da programmare lol). Funziona fondamentalmente come un Octree ma al contrario ... crea un elenco iniziale di colori e quindi divide l'elenco con il numero più alto di colori univoci per bit ordinati (con un numero di bit successivamente abbassato) in base alle esigenze fino a quando non ne ha tanti elenca come colori desiderati. Quindi restituisce un array contenente il colore medio da ciascun elenco ...

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;


namespace SeelWorks.Libraries.Imaging.Quantization {

    public static class BitSplitQuantizer {

        public static Color[] CreatePalette(IEnumerable<Color> sourceColors, int maxColors = 256) {
            var collections = new List<Collection>();
            collections.Add(new Collection());
            foreach(var _ in sourceColors) collections[0].Add(_);
            var offset = 1;
            while(collections.Count < maxColors) {
                if(offset > collections.Count) {
                    break;
                } else {
                    collections = collections.OrderBy(_ => _.Colors.Count).ToList();
                    var split = collections[collections.Count - offset].Split();
                    if((split.Count == 1) || ((collections.Count + split.Count - 1) > maxColors)) {
                        offset++;
                    } else {
                        offset = 1;
                        collections.RemoveAt(collections.Count - 1);
                        collections.AddRange(split);
                    }
                }
            }
            return collections.Select(_ => _.GetAverageColor()).ToArray();
        }


        private class Collection {
            public Dictionary<Color, int> Colors = new Dictionary<Color, int>();
            public int Level = -1;

            public void Add(Color color) {
                if(!Colors.ContainsKey(color)) Colors.Add(color, 0);
                Colors[color]++;
            }

            public List<Collection> Split() {
                var colors = Colors.OrderBy(_ => _.Value).Select(_ => _.Key).ToList();
                var level = (7 - Level - 1);
                var indexes = new int[8] { -1, -1, -1, -1, -1, -1, -1, -1 };
                var ret = new List<Collection>();
                foreach(var _ in colors) {
                    var index_ = ((((_.R >> level) & 1) << 2) | (((_.G >> level) & 1) << 1) | ((_.B >> level) & 1));
                    if(indexes[index_] == -1) {
                        ret.Add(new Collection());
                        indexes[index_] = (ret.Count - 1);
                        ret[ret.Count - 1].Level = (Level + 1);
                    }
                    ret[indexes[index_]].Colors[_] = Colors[_];
                }
                return ret;
            }

            public Color GetAverageColor() {
                var r = 0.0;
                var g = 0.0;
                var b = 0.0;
                var t = 0.0;
                foreach(var _ in Colors) {
                    r += (_.Key.R * _.Value);
                    g += (_.Key.G * _.Value);
                    b += (_.Key.B * _.Value);
                    t += _.Value;
                }
                return Color.FromArgb((int)Math.Round(r / t), (int)Math.Round(g / t), (int)Math.Round(b / t));
            }
        }

    }

}

Immagine originale:

Octree Quantized (0.145s):

BitSplit Quantized (0.100s):

Immagine originale:

Octree Quantized (0.233s):

BitSplit Quantized (0.213s):

Quindi sto provando a codificare alcuni file gif animati nella mia applicazione Java. Ho usato alcune classi / algoritmi trovati online, ma nessuno sembra funzionare abbastanza bene.

In questo momento sto usando questa classe di quantizzazione per ridurre a 256 i colori di un'immagine: http://www.java2s.com/Code/Java/2D-Graphics-GUI/Anefficientcolorquantizationalgorithm.htm

Il problema è che non sembra essere molto "intelligente".

Se passo un'immagine con più di 256 colori, riduce il numero del colore, ma non molto bene. (I rossi diventano blu, ecc. - errori molto evidenti come questo).

Esistono altri algoritmi / librerie per la quantizzazione dei colori in Java che puoi consigliare?

Nota: sono a conoscenza di Neuquant, utilizzato in questo algoritmo: http://www.java2s.com/Code/Java/2D-Graphics-GUI/AnimatedGifEncoder.htm

È molto lento e produce risultati "eh" (sfarfallio dei colori tra i frame).






quantization