53 votes

Défi de l'algorithme : Générer un schéma de couleurs à partir d'une image

Contexte

Donc, je travaille sur une nouvelle itération d'une application web. Et, nous avons découvert que nos utilisateurs sont obsédés par la paresse. Vraiment paresseux. En fait, plus nous faisons de travail pour eux, plus ils aiment le service. Une partie de l'application existante demande à l'utilisateur de sélectionner un schéma de couleurs à utiliser. Cependant, nous disposons d'une image (une capture d'écran du site Web de l'utilisateur), alors pourquoi ne pas satisfaire leur paresse et le faire pour eux ? Réponse : Nous pouvons le faire, et ce sera un exercice de programmation amusant :)

Le défi

À partir d'une image, comment créer une palette de couleurs correspondante ? En d'autres termes, comment sélectionner les X couleurs primaires d'une image (où X est défini par l'application web). L'image utilisée dans notre situation particulière est une capture d'écran du site Web de l'utilisateur, prise en pleine résolution (par exemple, 1280x1024). ( Note : Veuillez simplement décrire votre algorithme - il n'est pas nécessaire de poster un pseudocode réel).

Points bonus (points de crédibilité, pas de points SO réels) pour :

  • Description d'un algorithme qui est simple mais efficace. Le code est le moyen par lequel nous créons - gardez-le simple et beau.
  • Permettre à l'utilisateur de modifier le schéma de couleurs en fonction de diverses "humeurs" telles que "coloré", "brillant", "sourd", "profond", etc. Kuler )
  • Description d'une méthode permettant de déterminer de manière fiable la principale texte la couleur utilisée dans la capture d'écran du site web (qui nécessitera probablement un algo distinct).

Inspiration

Il existe plusieurs sites existants qui remplissent une fonction similaire. N'hésitez pas à les consulter et à vous demander : "Comment pourrais-je reproduire ce site ? Comment pourrais-je l'améliorer ?"

26voto

Paul Sonier Points 25528
  1. Pour trouver les couleurs primaires du X, faites un screencap de l'application. Lancez un histogramme des couleurs sur l'image. Les X couleurs supérieures dans l'histogramme sont le thème. Edit : si des gradients sont utilisés, vous voudrez choisir des "pics" de couleurs distincts ; c'est-à-dire que vous pouvez avoir tout un tas de couleurs autour de "orange" si l'orange est l'une des principales couleurs utilisées dans les gradients. En fait, il suffit de faire respecter une certaine distance entre les couleurs choisies dans l'histogramme.

  2. La modification du schéma de couleurs peut être effectuée au mieux dans l'espace HSV ; convertissez vos couleurs dans l'espace HSV, et si les utilisateurs veulent qu'elles soient plus "lumineuses", augmentez la valeur, s'ils veulent qu'elles soient plus "colorées", augmentez la saturation, etc.

  3. La meilleure façon de déterminer la couleur du texte est de caractériser les zones de haute variabilité (haute fréquence dans l'espace de Fourier). Dans ces zones, vous devriez avoir soit deux couleurs, texte et arrière-plan, auquel cas votre texte est la couleur la moins utilisée, soit plusieurs couleurs, texte et arrière-plan de l'image, auquel cas la couleur du texte est la couleur la plus courante.

7voto

Gemini420 Points 31

Je fais cela pour trouver la palette utilisée pour les images (des œuvres d'art).

  1. Je commence par utiliser Imagemagick et je redimensionne une grande image à une taille raisonnable (c'est-à-dire 400 px dans la plus grande dimension). Cela permet de convertir les subtiles différences de couleurs locales en un nombre réduit de pixels avec une moyenne de ces couleurs.

  2. Boucle à travers chaque pixel présent dans l'image redimensionnée, en lisant les valeurs RGB pour chaque pixel, convertit les RGB en HSB et stocke les valeurs HSB dans un tableau.

  3. Pour chaque couleur de pixel trouvée, je divise ensuite la plage de teinte (0,255) par 16, la plage de saturation (0,100) par 10 et la plage de luminosité (0,100) par 10. Arrondissez le résultat à un nombre entier supérieur ou inférieur. Cela permet de regrouper les pixels en catégories de couleurs similaires.

    Ainsi, un pixel avec un HSB de 223,64,76 serait dans la catégorie 14,6,8.

    Dans chaque catégorie, vous pouvez toujours trouver les couleur exacte de chaque pixel, mais pour la plupart, les catégories elles-mêmes sont une correspondance de couleur proche de l'image source.

    Choisissez de diviser le HSB en divisions plus fines si vous souhaitez une meilleure reproduction des couleurs des catégories. Par exemple, divisez chaque H,S,B par 8,5,5 au lieu de 16,10,10.

  4. Comptez les catégories de couleurs les plus répandues, triez et affichez. J'écarte les catégories de couleurs qui comptent très peu de pixels.

Note : Cette fonction est vraiment conçue pour les œuvres d'art qui ont très peu de pixels avec des valeurs de couleur identiques (c'est-à-dire les peintures avec des ombres et des dégradés).

Dans la plupart des cas, une page HTML comporte probablement plus de pixels qui correspondent exactement à une valeur de couleur spécifique (c'est-à-dire que la couleur de fond, la couleur du texte, etc. seront toutes de la même couleur où qu'elles apparaissent).

6voto

forresto Points 1783

Quantification des couleurs est le même processus que celui utilisé pour choisir la palette des GIF à faible intensité de couleur. Pour obtenir une palette de couleurs à partir d'une image photographique, j'ai utilisé l'outil de Nick Rabinowitz intitulé quantize.js qui est basé sur la MMCQ (modified median cut quantization) de Leptonica.

meemoo screen shot Application web en direct , à propos de .

5voto

maxwellb Points 3713
  1. Divisez l'image de l'écran en une grille de r-plusieurs rectangles, dans une "grille" de n par m, chacun ayant une largeur (largeur totale / n) et une hauteur (hauteur totale / m).

    1a. Attribuez un poids aux zones les plus visibles de l'écran, comme la zone décentrée à gauche.

    1b. Pour chaque rectangle, affectez les pixels dans un espace de ( couleur , fréquence )

  2. Pour chaque rectangle R, la distribution de fréquence f_R, et le poids W_R :

    2a. Déterminez le i -ème couleur de schéma (par exemple i = 1 <--> couleur de fond) en balayant la "fréquence supérieure", la "deuxième fréquence" ( c'est-à-dire f_R[ i , :]) pour chaque bloc.

    2b. Pour chaque i et le mettre dans un tableau de scores, ( couleur_i , score ) où score = f_R[ i , "fréquence"] * W_R

    2c. Le meilleur score de chaque i sera le i -la couleur du schéma.

En théorie, si vous avez beaucoup de "bleu sur blanc" ou de "rouge sur noir", vous devriez obtenir un primaire blanc, un secondaire bleu, ou un primaire noir, un secondaire rouge, par exemple.

Pour la couleur de votre texte, vous pouvez soit la baser directement sur un calcul de la couleur d'arrière-plan, soit choisir une couleur secondaire et, si la différence V de HSV est trop faible, baser la couleur sur la couleur du schéma calculé, mais augmenter la valeur V.

PseudoCode :

float[][] weights = 
    { { 1.0, 3.0, 5.0, 5.0, 3.0, 1.0, 1.0, 1.0, 1.0 },
      { 2.0, 6.0, 7.0, 7.0, 6.0, 2.0, 3.0, 3.0, 2.0 },
      { 2.0, 8.0, 9.0, 9.0, 7.0, 3.0, 6.0, 6.0, 3.0 },
      { 2.0, 8.0, 9.0, 9.0, 7.0, 2.0, 3.0, 3.0, 2.0 },
      { 2.0, 7.0, 9.0, 9.0, 7.0, 2.0, 1.0, 1.0, 1.0 },
      { 2.0, 6.0, 7.0, 7.0, 6.0, 2.0, 3.0, 3.0, 1.0 },
      { 1.0, 3.0, 5.0, 5.0, 3.0, 2.0, 6.0, 6.0, 2.0 },
      { 1.0, 1.0, 2.0, 2.0, 1.0, 2.0, 6.0, 6.0, 2.0 },
      { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 3.0, 1.0 } };

// Leave the following implementations to the imagination:
void DivideImageIntoRegions( Image originalImage, out Image[][] regions );
void GetNthMostCommonColorInRegion( Image region, int n, out Color color );
TKey FindMaximum<TKey, TValue>( Map<TKey, TValue> map );

// The method:
Color[] GetPrimaryScheme( Image image, int ncolors, int M = 9, int N = 9 )
{
    Color[] scheme = new Color[ncolors];
    Image[][] regions = new Image[M][N];

    DivideImageIntoRegions( image, regions );

    for( int i = 0; i < ncolors; i++ )
    {
        Map<Color, float> colorScores = new Map<Color, float>();

        for( int m = 0; m < M; m++ )
        for( int n = 0; n < N; n++ )
        {
            Color theColor;
            GetNthMostCommonColorInRegion( region, i, theColor );

            if( colorScores[theColor] == null )
            { colorScores[theColor] = 0; }

            colorScores[theColor] += weights[m][n];
        }

        scheme[i] = FindMaximum( colorScores );
    }

    return scheme;
}

En regardant ce qui précède, il est clair que s'il y a une région avec peu de variabilité, elle aura la même deuxième couleur la plus commune que la couleur la plus commune. Pour ajuster, la deuxième couleur la plus commune dans un tel cas pourrait être nulle, ce dont on pourrait se prémunir :

            if( theColor != null )
                continue;

            if( colorScores[theColor] == null )
            { colorScores[theColor] = 0; }

            colorScores[theColor] += weights[m][n];
        }

4voto

Lasse V. Karlsen Points 148037

Le nom du type d'algorithme que vous souhaitez est le suivant Quantification des couleurs .

Malheureusement je n'ai pas de code source disponible pour vous, mais je suis sûr qu'une recherche google pourrait trouver quelque chose.

En particulier, le Article du Dr. Dobb's Journal sur le sujet semble prometteur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X