Question

Pour un projet de loisir, je vais créer un programme qui, lorsqu'un bitmap d'image sera créé, créera un motif de points de croix en tant que PDF. Je vais utiliser Cocoa / Objective C sur un Mac.

Le bitmap source sera généralement une image 24bpp, mais parmi les millions de couleurs disponibles, seules quelques-unes existent en tant que fils de point de croix. Les fils sont de différents types. Le format DMC est le plus largement disponible, et la quasi-totalité de leur gamme est disponible sous forme de valeurs RVB à partir de divers sites Web. En voici un , par exemple.

DMC#  Name               R   G   B
----- ------------------ --- --- ---
blanc White              255 255 255
208   Lavender - vy dk   148  91 128
209   Lavender - dk      206 148 186
210   Lavender - md      236 207 225
211   Lavender - lt      243 218 228
      ...etc...

Mon premier problème, selon moi, provient d'un point de départ du RVB à partir d'un pixel de l'image en choisissant la couleur la plus proche disponible dans l'ensemble DMC. Quel est le meilleur moyen de trouver mathématiquement la couleur DMC la plus proche et de s’assurer qu’elle s’agence également comme couleur?

Bien que j'utilise Cocoa, n'hésitez pas à utiliser un pseudo-code (ou même Java!) dans tout code que vous publiez.

Était-ce utile?

La solution

Utilisez l'espace de couleur LAB pour trouver la couleur avec le distance euclidienne . Faire cela dans l'espace colorimétrique RVB donnera des résultats contre-intuitifs. (Ou utilisez l'espace colorant HSL .)

Il vous suffit donc de parcourir chaque pixel et de trouver la couleur dont la distance est la plus proche dans l’espace colorimétrique que vous avez choisi. Notez que la distance doit être calculée circulairement pour certains espaces colorimétriques (par exemple, ceux qui utilisent hue ).

(La plupart des couleurs sont utilisées pour choisir une palette, mais dans votre cas, cela a déjà été réglé, vous ne pouvez donc pas utiliser les techniques de quantification les plus répandues.)

Vérifiez également cette question .

Pour trouver la teinte HSB dans Cocoa, vous pouvez utiliser le Méthode getHue déclarée dans NSColor.h .

Toutefois, si vous convertissez simplement une image en motif de croix à l'aide de cette technique, il sera très difficile de la coudre. Elle sera remplie de champs de couleur à pixel unique, qui défait en quelque sorte le but du point de croix.

Autres conseils

Cette opération s'appelle quantification des couleurs , et de nombreux algorithmes sont disponibles.

Un principe de base consiste à traiter les couleurs RVB comme des points dans l’espace et à utiliser la vieille distance euclidienne simple pour comprendre comment "fermer" les couleurs. elles sont. Cela présente des inconvénients, car les yeux des hommes ont une sensibilité différente en différents endroits de cet espace, de sorte qu'une telle distance ne correspondrait pas bien à la façon dont les humains perçoivent les couleurs. Vous pouvez utiliser différents systèmes de pondération pour améliorer cette situation.

Interressant ...:)

Non seulement vous identifieriez les couleurs les plus proches, mais vous voudriez aussi réduire le nombre de couleurs utilisées. Vous ne voulez pas vous retrouver avec un motif d'assemblage qui utilise des centaines de couleurs différentes ...

J'ai mis en place un code qui fait cela à un niveau basique. (Désolé que ce soit en C #, j'espère que cela pourra être utile quand même.)

Bien sûr, il reste quelques modifications à apporter avant que la méthode fonctionne correctement. La méthode GetDistance pondère l’importance de la teinte, de la saturation et de la luminosité, il est bien sûr important de trouver le meilleur équilibre entre celles-ci afin de trouver la couleur la plus proche.

Il y a aussi beaucoup à faire avec la méthode de réduction de la palette. Dans l'exemple, je viens de choisir les couleurs les plus utilisées, mais vous souhaitez probablement déterminer le degré de similitude des couleurs dans la palette. Pour ce faire, sélectionnez la couleur la plus utilisée, réduisez le nombre de couleurs restantes dans la liste en fonction de la distance qui le sépare, puis utilisez la liste.

La classe Hsl qui contient une couleur DMC, peut calculer la distance d’une autre couleur et rechercher la couleur la plus proche dans une liste de couleurs:

public class Hsl {

    public string DmcNumber { get; private set; }
    public Color Color { get; private set; }
    public float Hue { get; private set; }
    public float Saturation { get; private set; }
    public float Brightness { get; private set; }
    public int Count { get; set; }

    public Hsl(Color c) {
        DmcNumber = "unknown";
        Color = c;
        Hue = c.GetHue();
        Saturation = c.GetSaturation();
        Brightness = c.GetBrightness();
        Count = 0;
    }

    public Hsl(string dmc, int r, int g, int b)
        : this(Color.FromArgb(r, g, b))
    {
        DmcNumber = dmc;
    }

    private static float AngleDifference(float a1, float a2) {
        float a = Math.Abs(a1 - a2);
        if (a > 180f) {
            a = 360f - a;
        }
        return a / 180f;
    }

    public float GetDistance(Hsl other) {
        return
            AngleDifference(Hue, other.Hue) * 3.0f +
            Math.Abs(Saturation - other.Saturation) +
            Math.Abs(Brightness - other.Brightness) * 4.0f;
    }

    public Hsl GetNearest(IEnumerable<Hsl> dmcColors) {
        Hsl nearest = null;
        float nearestDistance = float.MaxValue;
        foreach (Hsl dmc in dmcColors) {
            float distance = GetDistance(dmc);
            if (distance < nearestDistance) {
                nearestDistance = distance;
                nearest = dmc;
            }
        }
        return nearest;
    }

}

Ce code établit une liste (fortement réduite) de couleurs DMC, charge une image, compte les couleurs, réduit la palette et convertit l'image. Vous voudrez bien sûr également enregistrer les informations de la palette réduite quelque part.

Hsl[] dmcColors = {
    new Hsl("blanc", 255, 255, 255),
    new Hsl("310", 0, 0, 0),
    new Hsl("317", 167, 139, 136),
    new Hsl("318", 197, 198, 190),
    new Hsl("322", 81, 109, 135),
    new Hsl("336", 36, 73, 103),
    new Hsl("413", 109, 95, 95),
    new Hsl("414", 167, 139, 136),
    new Hsl("415", 221, 221, 218),
    new Hsl("451", 179, 151, 143),
    new Hsl("452", 210, 185, 175),
    new Hsl("453", 235, 207, 185),
    new Hsl("503", 195, 206, 183),
    new Hsl("504", 206, 221, 193),
    new Hsl("535", 85, 85, 89)
};

Bitmap image = (Bitmap)Image.FromFile(@"d:\temp\pattern.jpg");

// count colors used
List<Hsl> usage = new List<Hsl>();
for (int y = 0; y < image.Height; y++) {
    for (int x = 0; x < image.Width; x++) {
        Hsl color = new Hsl(image.GetPixel(x, y));
        Hsl nearest = color.GetNearest(dmcColors);
        int index = usage.FindIndex(h => h.Color.Equals(nearest.Color));
        if (index != -1) {
            usage[index].Count++;
        } else {
            nearest.Count = 1;
            usage.Add(nearest);
        }
    }
}

// reduce number of colors by picking the most used
Hsl[] reduced = usage.OrderBy(c => -c.Count).Take(5).ToArray();

// convert image
for (int y = 0; y < image.Height; y++) {
    for (int x = 0; x < image.Width; x++) {
        Hsl color = new Hsl(image.GetPixel(x, y));
        Hsl nearest = color.GetNearest(reduced);
        image.SetPixel(x, y, nearest.Color);
    }
}

image.Save(@"d:\temp\pattern.png", System.Drawing.Imaging.ImageFormat.Png);

obtenir le source de l'application ppmquant à partir de netpbm ensemble d'utilitaires

D'autres ont signalé diverses techniques de quantification des couleurs. Il est possible d'utiliser des techniques telles que les champs aléatoires de Markov pour tenter de pénaliser le système en modifiant les couleurs de fil aux emplacements de pixels voisins. Il existe certaines bibliothèques MRF génériques multi-étiquettes, notamment les Boykov's .

Pour utiliser l'un de ces éléments, les éléments de données seraient les couleurs d'entrée, les étiquettes seraient l'ensemble des couleurs de fil, les termes de données pourraient être quelque chose comme la distance euclidienne dans l'espace LAB suggérée par bzlm, et les termes de voisinage pénaliser pour changer de couleur de fil.

En fonction de la pertinence de vos opérations sur les couleurs, n'oubliez pas de prendre l'espace colorimétrique . s en compte. Bien que j'aie étudié cela un peu, à cause de mon passe-temps photographique, je suis encore un peu confus à propos de tout.

Mais, comme mentionné précédemment, utilisez LAB autant que possible, car, autant que ce soit, son agnostique est coloré, alors que toutes les autres méthodes (RVB / HSL / CMJN) ne signifient rien (en théorie) sans un espace colorimétrique défini.

RVB, par exemple, ne représente que trois valeurs de pourcentage (0-255 = & 0 à 100%, avec une profondeur de couleur de 8 bits). Ainsi, si vous avez un triplet RVB de (0,255,0), il se traduit par "uniquement du vert et autant que possible". Ainsi, la question est "comment le rouge est-il rouge?" C’est la question à laquelle répond l’espace colorimétrique - sRGB Le vert 100% n'est pas aussi vert que AdobeRGB 100% vert. Ce n'est même pas la même teinte !

Désolé si cela s'est passé du côté offtopic des choses

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top