Domanda

Sto cercando di capire come assaggiare tutti i pixel in un'immagine e generare una tavolozza di colori da esso, qualcosa come questo o questo. Non ho idea di dove iniziare. Qualcuno può indicarmi nella giusta direzione?

__MODIFICARE: __

Questo è ciò che ho finito finora:

L'ho usato Pixelato Funzione per ottenere sezioni di blocco di grandi dimensioni come suggerito da Joe_Coolish. Funziona perfettamente e mi dà un ottimo campione di colori con cui lavorare (questo è dal campione di finestre Jelly Fish Picture):

Ora, se qualcuno potesse aiutarmi a ottenere i 5 colori più distinti (blu più scuro, blu più leggero, arancione, grigio e pesca (?)), Ti amerei per sempre. Davvero non capisco come farlo media o Inserisci colori insieme. Inoltre, non riesco a capire come dire se un colore è simile programmaticamente, ci sono molti numeri e variabili in te spiegazioni che mi perdo nel tentativo di capire cosa sta facendo cosa a chi.

È stato utile?

Soluzione

Le risposte che coinvolgono il codice ti mostrano come ottenere la tavolozza completa. Se vuoi ottenere i colori medi come nei siti Web che hai pubblicato, è così che lo farei.

Immagine della fonte:

Source

Innanzitutto, vorrei in media i colori applicando un filtro passa -basso (qualcosa come una sfocatura gaussiana)

enter image description here

In questo modo stai limitando la tavolozza totale. Da lì dividerei lo schermo in n blocchi (n essendo il numero totale di pixel che desideri nella tua tavolozza)

enter image description here

Da lì, target ogni blocco e itera su ogni pixel e prendi il pixel medio per quel blocco e aggiungilo all'indice della palette. Il risultato è qualcosa di simile:

enter image description here

In questo modo la tua tavolozza è limitata e ottieni i colori medi dalle diverse regioni. Puoi fare tutto questo nel codice e se vuoi un aiuto con quello, fammi sapere e ne posterò un po '. Questo è solo il livello di alto livello "quello che farei".

Altri suggerimenti

Innanzitutto, prendi i pixel nella foto: (presuppone using System.Drawing.Imaging; e 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);

Quindi puoi creare la tua tavolozza:

var distinctColors = arr.Distinct();

Facoltativamente: elimina colori simili fino a quando non hai la dimensione della tavolozza preferita. Ecco come potresti farlo (anche se questo non è sicuramente il modo più efficiente o accurato, solo il più semplice):

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

È probabile in qualsiasi immagine ricca che la maggior parte dei tuoi colori sarà unica in qualche modo. Seguirebbe, quindi, che recuperare colori distinti probabilmente non ti aiuterà a raggiungere il tuo obiettivo.

Consiglio di ispezionare i valori HSV per ogni pixel nella tua immagine. Ti lascio a innumerevoli esempi online di recupero di immagini come matrici di valori HSV.

Con i tuoi valori HSV, puoi calcolare i cluster di tonalità prominenti creando un array intero di 256 conteggi di tonalità, calcolando un istogramma di tonalità nei dati dell'immagine. È possibile determinare tonalità di spicco trovando cluster di tonalità sequenziali 4-6 con una somma di conteggio elevato.

Dopo aver raccolto diverse tonalità di spicco, suddividere i pixel di quelle tonalità in un altro istogramma di misurazione della saturazione e scegliere cluster di spicco e così via.

Esempio approssimativo

Il codice seguente fa qualche tentativo di aiutare a identificare le tonalità di spicco. Molto probabilmente ci sono altri modi fantastici per farlo; Tuttavia, questo può fornire alcune idee.

Innanzitutto, ottengo tutti i colori dell'immagine come una matrice di Color Oggetti, così:

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;
    }
}

Potresti considerare di convalidare che ho ottenuto l'ordine di RGB nel Color.FromArgb Metodo Chiama nell'ordine corretto.

Successivamente, metto da parte un metodo di utilità per la conversione in HSV. Nel mio esempio, lavorerò solo con le tonalità, ma ecco un esempio funzionante della conversione:

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);
}

Infine, costruisco l'istogramma della tonalità, definisco una larghezza di tonalità (diciamo, 9 tonalità) in cui aggregare i conteggi insieme, e quindi riporta i conteggi alla 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]);
    }
}

Non ho fatto alcun tentativo di filtrare quale tonalità da scegliere. Potrebbe essere necessario considerare un po 'di euristica piuttosto che raccogliere ciecamente i conteggi più grandi, perché probabilmente vuoi scegliere tonalità che sono in qualche modo separate sullo spettro del colore. Non ho tempo di esplorarlo oltre, ma spero che ciò fornisca una visione di una strategia che puoi considerare.

Ho iniziato qui:

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

I'm going to describe the best approach at a very high level.

First you construct a histogram of colors in the picture and their frequency.

You end up with a list of all colors in the image, you can use data clustering to find candidate colors to merge. Colors that are merged together into a weighted average based on the frequency of the original colors.

This way you can incrementally decrease the palette to a desired fidelity, while preserving high contrast but fine details and only losing fidelity where the gradients are much more subtle.

Once you have the reduced palette, you recolor the picture using the nearest neighbor color that is in the palette.

The K-Means clustering algorithm works well for this problem. It does a great job of extracting centroids of image color clusters, but be aware that its non-deterministic behavior makes determining the actual prominence of each cluster difficult.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top