Question

Je suis en train de comprendre comment échantillonner tous les pixels dans une image et générer une palette de couleurs de celui-ci, quelque chose comme ce ou cette . Je ne sais pas où commencer même. point que quelqu'un peut me dans la bonne direction?

__ EDIT: __

Voici ce que j'ai fini avec ce jour:

J'ai utilisé cette fonction Pixelate obtenir de grandes sections de bloc comme joe_coolish proposées. Cela fonctionne parfaitement et me donner un assez bon échantillon de couleurs pour travailler avec (ce qui est de l'échantillon windows image gelée de poissons):

Maintenant, si quelqu'un pouvait me aider à obtenir les 5 couleurs les plus distinctes (le plus sombre bleu, plus léger bleu, orange, gris et pêche (?)), Je vous aimerai toujours. Je ne comprends vraiment pas comment moyenne ou ajouter couleurs ensemble. Je ne peux pas non comprendre comment savoir si une couleur est similaire programatically, il y a quelques chiffres et beaucoup de variables dans les explications que je vous Perdez à essayer de comprendre ce qui fait quoi à qui.

Était-ce utile?

La solution

Les réponses concernant le code que vous montrer comment obtenir la palette complète. Si vous voulez obtenir les couleurs moyennes comme dans les sites où vous avez posté, voici comment je le ferais.

Image Source:

Source

Tout d'abord, je voudrais en moyenne les couleurs en appliquant un filtre passe-bas (quelque chose comme un flou gaussien)

entrer image description ici

De cette façon, vous limitez la palette totale. De là, je diviser l'écran en blocs N (N étant le nombre total de pixels que vous voulez dans votre palette)

entrer image description ici

A partir de là, chaque bloc cible et itérer sur chaque pixel, et obtenir le pixel moyen pour ce bloc et l'ajouter à l'index de la palette. Le résultat est quelque chose comme ceci:

entrer image description ici

De cette façon, votre palette est limitée et vous obtenez les couleurs moyennes des différentes régions. Vous pouvez faire tout cela dans le code, et si vous souhaitez un peu d'aide avec cela, laissez-moi savoir et je vais poster quelques-uns. Ceci est juste le haut niveau « ce que je ferais ».

Autres conseils

En premier lieu, prendre les pixels dans l'image: (suppose using System.Drawing.Imaging; et using System.Runtime.InteropServices)

Bitmap b = new Bitmap(myImage);
BitmapData bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, ImageFormat.Format32Bpp);
int[] arr = new int[bd.Width * bd.Height - 1];
Marshal.Copy(bd.Scan0, arr, 0, arr.Length);
b.UnlockBits(bd);

Ensuite, vous pouvez créer votre palette:

var distinctColors = arr.Distinct();

En option: Éliminer des couleurs similaires jusqu'à ce que vous avez la taille de votre palette préférée. Voici comment vous pourriez le faire (bien que ce soit certainement pas la façon la plus efficace ou précis, juste le plus simple):

var dc = distinctColors.toArray(); // int dc[] = distinctColors.toArray() is what it used to be
int cmIndex1 = -1;
int cmIndex2 = -1;
int cmDiff = -1;
for (int i = 0; i < dc.length; i++) {
    Color c1 = Color.FromArgb(dc[i]);
    for (int j = i + 1; j < dc.length; j++) {
        Color c2 = Color.FromArgb(dc[j]);
        // Note: you might want to include alpha below
        int diff = Math.Abs(c1.R - c2.R) + Math.Abs(c1.G - c2.G) + Math.Abs(c1.B - c2.B);
        if (cmDiff < 0 || diff < cmDiff) {
            cmIndex1 = i;
            cmIndex2 = j;
            cmDiff = diff;
        }
    }
}
// Remove the colors, replace with average, repeat until you have the desired number of colors

Il est probable dans une image riche que la plupart de vos couleurs sera unique en quelque sorte. Il suivrait donc que l'extraction des couleurs distinctes ne sera probablement pas vous aider à atteindre votre objectif.

Je recommande l'inspection des valeurs de HSV pour chaque pixel dans l'image. Je vous laisse à d'innombrables exemples en ligne de récupération d'images sous forme de tableaux de valeurs HSV.

Avec vos valeurs HSV, vous pouvez calculer des grappes de teintes de premier plan de créer un tableau entier de 256 points de teinte, le calcul d'un histogramme des couleurs dans vos données d'image. Vous pouvez déterminer les teintes de premier plan en trouvant des grappes de 4-6 teintes successives avec une somme élevée de comptage.

Après avoir sélectionné plusieurs teintes de premier plan, des pixels Subdiviser de ces teintes dans une autre saturation de mesure de l'histogramme, et choisir des groupes importants, et ainsi de suite.

Exemple Rugueux

Le code ci-dessous fait une tentative pour aider à identifier les teintes importantes. Il y a très probablement d'autres moyens impressionnants pour ce faire; Cependant, cela peut donner quelques idées.

Tout d'abord, je reçois toutes les couleurs de l'image comme un tableau d'objets Color, comme suit:

private static Color[] GetImageData(Image image)
{
    using (var b = new Bitmap(image))
    {
        var bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
        byte[] arr = new byte[bd.Width * bd.Height * 3];
        Color[] colors = new Color[bd.Width * bd.Height];
        Marshal.Copy(bd.Scan0, arr, 0, arr.Length);
        b.UnlockBits(bd);

        for (int i = 0; i < colors.Length; i++)
        {
            var start = i*3;
            colors[i] = Color.FromArgb(arr[start], arr[start + 1], arr[start + 2]);
        }

        return colors;
    }
}

Vous pourriez envisager de valider que je suis l'ordre de RVB dans la méthode Color.FromArgb appel dans le bon ordre.

Ensuite, je planque de côté une méthode utilitaire pour la conversion de HSV. Dans mon exemple, je travaille uniquement avec des teintes, mais voici un exemple de travail complet de la conversion:

private static void ColorToHSV(Color color, out int hue, out int saturation, out int value)
{
    int max = Math.Max(color.R, Math.Max(color.G, color.B));
    int min = Math.Min(color.R, Math.Min(color.G, color.B));

    hue = (int)(color.GetHue() * 256f / 360f);
    saturation = (max == 0) ? 0 : (int)(1d - (1d * min / max));
    value = (int)(max / 255d);
}

Enfin, je construis l'histogramme teinte, définir une largeur de teintes (par exemple, 9 teintes) dans lequel des chiffres agrégés ensemble, puis-je signaler les comptes à la console.

private static void ProcessImage(Color[] imagecolors)
{
    var hues = new int[256];
    var hueclusters = new int[256];
    int hue, saturation, value;

    // build hue histogram.
    foreach (var color in imagecolors) {
        ColorToHSV(color, out hue, out saturation, out value);
        hues[hue]++;
    }

    // calculate counts for clusters of colors.
    for (int i = 0; i < 256; i++) {
        int huecluster = 0;
        for (int count = 0, j = i; count < 9; count++, j++) {
            huecluster += hues[j % 256];
        }

        hueclusters[(i + 5) % 256] = huecluster;
    }

    // Print clusters on the console
    for (int i = 0; i < 256; i++) {
        Console.WriteLine("Hue {0}, Score {1}.", i, hueclusters[i]);
    }
}

Je l'ai fait aucune tentative pour filtrer jusqu'à qui teintes au choix. Vous devrez peut-être envisager des heuristiques plutôt que de choisir aveuglément haut ce qu'on compte beaucoup, parce que vous voulez probablement choisir des teintes qui sont un peu séparés sur le spectre des couleurs. Je n'ai pas le temps d'explorer cette plus loin, mais j'espère que cela donne un aperçu d'une stratégie que vous pouvez envisager.

Je commence ici:

System.Drawing.Image img = System.Drawing.Bitmap.FromFile("file");
System.Drawing.Imaging.ColorPalette palette = img.Palette;
foreach (Color color in palette.Entries)
{
  //...
}

Je vais décrire la meilleure approche à un niveau très élevé.

D'abord, vous construire un histogramme de couleurs dans l'image et leur fréquence.

Vous vous retrouvez avec une liste de toutes les couleurs dans l'image, vous pouvez utiliser le regroupement de données pour trouver des couleurs candidats à la fusion. Les couleurs qui sont fusionnées en une moyenne pondérée en fonction de la fréquence des couleurs d'origine.

De cette façon, vous pouvez diminuer progressivement la palette à une fidélité désirée, tout en conservant un contraste élevé, mais les détails fins et seulement de perdre la fidélité où les gradients sont beaucoup plus subtiles.

Une fois que vous avez la palette réduite, vous recolorer l'image en utilisant la couleur du plus proche voisin qui se trouve dans la palette.

Le K-Means algorithme de classification fonctionne bien pour ce problème. Il fait un excellent travail d'extraction centroïdes des grappes de couleur d'image, mais il faut savoir que son comportement non déterministe permet de déterminer l'importance réelle de chaque groupe difficile.

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