Ejemplo n.º 1
0
        public Color[] GenerateKMean(int colorsCount,
            PaletteOptions options = null,
            ColorDistanceType distanceType = ColorDistanceType.Default)
        {
            options = options ?? PaletteOptions.GetDefault();
            var kMeans = new List<LabColor>();
            for (var i = 0; i < colorsCount; i++)
            {
                var lab = LabColor.GetRandom();
                while (!lab.IsValidRgb())
                {
                    lab = LabColor.GetRandom();
                }
                kMeans.Add(lab);
            }

            var colorSamples = GenerateColorSamples(options);

            // Steps
            var steps = options.Quality;
            var samplesCount = colorSamples.Count;
            var samplesClosest = new int?[samplesCount];
            while (steps-- > 0)
            {
                // kMeans -> Samples Closest
                for (var i = 0; i < samplesCount; i++)
                {
                    var lab = colorSamples[i];
                    var minDistance = double.MaxValue;
                    for (var j = 0; j < kMeans.Count; j++)
                    {
                        var kMean = kMeans[j];
                        var distance = GetColorDistance(lab, kMean, distanceType);
                        if (distance < minDistance)
                        {
                            minDistance = distance;
                            samplesClosest[i] = j;
                        }
                    }
                }
                // Samples -> kMeans
                var freeColorSamples = colorSamples
                    .Select((lab) => (LabColor)lab.Clone()) // todo do I really need clone each item?
                    .ToList();
                for (var j = 0; j < kMeans.Count; j++)
                {
                    var count = 0;
                    var candidateKMean = new LabColor();
                    for (var i = 0; i < colorSamples.Count; i++)
                    {
                        if (samplesClosest[i] == j)
                        {
                            count++;
                            var color = colorSamples[i];
                            candidateKMean.L += color.L;
                            candidateKMean.A += color.A;
                            candidateKMean.B += color.B;
                        }
                    }
                    if (count != 0)
                    {
                        candidateKMean.L /= count;
                        candidateKMean.A /= count;
                        candidateKMean.B /= count;
                    }

                    if (count != 0 && 
                        candidateKMean.IsValidRgb() &&
                        options.ValidateColor(candidateKMean))
                    {
                        kMeans[j] = candidateKMean;
                    }
                    else
                    {
                        // The candidate kMean is out of the boundaries of the color space, or unfound.
                        if (freeColorSamples.Count > 0)
                        {
                            // We just search for the closest FREE color of the candidate kMean
                            var minDistance = double.MaxValue;
                            var closest = -1;
                            for (var i = 0; i < freeColorSamples.Count; i++)
                            {
                                var distance = GetColorDistance(freeColorSamples[i], candidateKMean, distanceType);
                                if (distance < minDistance)
                                {
                                    minDistance = distance;
                                    closest = i;
                                }
                            }
                            kMeans[j] = colorSamples[closest];
                        }
                        else
                        {
                            // Then we just search for the closest color of the candidate kMean
                            var minDistance = double.MaxValue;
                            var closest = -1;
                            for (var i = 0; i < colorSamples.Count; i++)
                            {
                                var distance = GetColorDistance(colorSamples[i], candidateKMean, distanceType);
                                if (distance < minDistance)
                                {
                                    minDistance = distance;
                                    closest = i;
                                }
                            }
                            kMeans[j] = colorSamples[closest];
                        }
                    }
                    var baseColor = kMeans[j];
                    freeColorSamples = freeColorSamples
                        .Where((lab) => !lab.Equals(baseColor))
                        .ToList();
                }
            }
            return kMeans.Select((lab) => lab.ToRgb()).ToArray();
        }
Ejemplo n.º 2
0
        public Color[] GenerateForce(int colorsCount,
            PaletteOptions options = null,
            ColorDistanceType distanceType = ColorDistanceType.Default)
        {
            var random = new Random();
            var colors = new LabColor[colorsCount];
            options = options ?? PaletteOptions.GetDefault();
            // Init
            for (var i = 0; i < colorsCount; i++)
            {
                // Find a valid Lab color
                var color = LabColor.GetRandom();
                while (color.IsValidRgb() || options.ValidateColor(color))
                {
                    color = LabColor.GetRandom();
                }
                colors[i] = color;
            }

            // Force vector: repulsion
            var repulsion = 100;
            var speed = 100;
            var steps = options.Quality * 20;
            var vectors = new LabVector[colorsCount];
            while (steps-- > 0)
            {
                // Init
                for (var i = 0; i < colors.Length; i++)
                {
                    vectors[i] = new LabVector();
                }
                // Compute Force
                for (var i = 0; i < colors.Length; i++)
                {
                    var colorA = colors[i];
                    for (var j = 0; j < i; j++)
                    {
                        var colorB = colors[j];

                        // repulsion force
                        var dl = colorA.L - colorB.L;
                        var da = colorA.A - colorB.A;
                        var db = colorA.B - colorB.B;
                        var d = GetColorDistance(colorA, colorB, distanceType);
                        if (d > 0)
                        {
                            var force = repulsion / Math.Pow(d, 2);

                            vectors[i].dL += dl * force / d;
                            vectors[i].dA += da * force / d;
                            vectors[i].dB += db * force / d;

                            vectors[j].dL -= dl * force / d;
                            vectors[j].dA -= da * force / d;
                            vectors[j].dB -= db * force / d;
                        }
                        else
                        {
                            // Jitter
                            vectors[j].dL += 2 - 4 * random.NextDouble();
                            vectors[j].dA += 2 - 4 * random.NextDouble();
                            vectors[j].dB += 2 - 4 * random.NextDouble();
                        }
                    }
                }
                // Apply Force
                for (var i = 0; i < colors.Length; i++)
                {
                    var color = colors[i];
                    var displacement = speed * vectors[i].Magnitude; ;
                    if (displacement > 0)
                    {
                        var ratio = speed * Math.Min(0.1, displacement) / displacement;
                        var l = color.L + vectors[i].dL * ratio;
                        var a = color.A + vectors[i].dA * ratio;
                        var b = color.B + vectors[i].dB * ratio;
                        var candidateLab = new LabColor(l, a, b);
                        if (candidateLab.IsValidRgb() && options.ValidateColor(candidateLab))
                        {
                            colors[i] = candidateLab;
                        }
                    }
                }
            }

            return colors.Select((lab) => lab.ToRgb()).ToArray();
        }