Dégradé de couleurs

Le problème exposé dans ce sujet a été résolu.

Bonjour à tous,

Je souhaite réaliser un dégradé horizontal de couleurs arc-en-ciel (allant du rouge au rouge, en passant par le jaune, vert…). Ce dernier possède une largeur qui est choisie par l'utilisateur-final.

Pour ce faire j'aurais besoin de vos conseils, en effet :

  1. Je parcours l'image, qui est vierge au début, pixel par pixel de haut en bas PUIS de gauche à droite (autrement dit je dessine une ligne verticale, puis je passe au pixel de droite et je redessine une ligne verticale, et ainsi de suite).

  2. Or l'utilisateur-final peut choisir, à la création de cette image, la taille de cette dernière (et donc du dégradé, car le dégradé EST l'image).

  3. Donc : la ligne verticale d'une couleur donnée (prenons le rouge de départ) n'aura pas juste une largeur de 1, mais de xxx pixels. Comment déterminer ces xxx pixels ? La solution suivante est impossible : connaissant la largeur du dégradé en pixels, et le nombre de couleurs, on peut connaître le nombre de pixels par couleurs. Elle est "impossible" car le nombre de couleurs n'est pas déterminable (enfin c'est évident, puisque c'est un dégradé…). Du coup je ne vois pas comment faire.

  4. Enfin, j'ai remarqué qu'il n'y a qu'une seule composante à la fois qui est changée au fur et à mesure qu'un dégradé est fait : d'abord RED = 255, puis ensuite on modifie UNIQUEMENT GREEN (en l'augmentant), puis on modifie UNIQUEMENT RED (en le baissant), etc. Il faudrait que je trouve une fonction (une application plus précisément) qui associe au pixel-abscisse la bonne valeur à la bonne composante. Comment choisir cette composante ? Le choix de la "bonne valeur" me semble simple.

Par ailleurs, j'utilise le système RGB et le dégradé se limite aux couleurs saturées.

Voici ce que je voudrais obtenir : http://fr.flossmanuals.net/processing/les-couleurs/static/Processing-Couleurs-color_spectrum-tiff-fr-old.png

Merci beaucoup !

EDIT IMPORTANT :

Topic résolu ! Source :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public void displayHorGraduation(String type) {
        double w = this.writable_image.getWidth();
        double r = 0, g = 0, b = 0;
        for(int x = 0; x < this.writable_image.getWidth(); x++) {
            for (int y = 0; y < this.writable_image.getHeight(); y++) {

                if(type.equals("Blanc vers noir")) {
                    this.writable_pixel_writer.setColor(x, y, Color.color(-x/w + 1, -x/w + 1, -x/w + 1));
                } else if(type.equals("Noir vers blanc")) {
                    this.writable_pixel_writer.setColor(x, y, Color.color(x/w, x/w, x/w));
                } else if(type.equals("Polychrome")) {

                    if(x >= 0 && x < w/6) {
                        r = 255;
                        g = 1530*x/w;
                    }

                    if(x >= 0 && x < 2*w/6) {
                        b = 0;
                    }

                    if(x >= 2*w/6 && x < 3*w/6) {
                        b = 1530*x/w - 510;
                    }

                    if(x >= 3*w/6 && x < 5*w/6) {
                        b = 255;
                    }

                    if(x >= 5*w/6 && x <= w) {
                        b = -1530*x/w + 1530;
                    }

                    if (x >= w/6 && x < 3*w/6) {
                        g = 255;
                    }

                    if(x >= 3*w/6 && x < 4*w/6) {
                        g = -1530*x/w + 1020;
                    }

                    if(x >= 4*w/6 && x <= w) {
                        g = 0;
                    }

                    if(x >= w/6 && x < 2*w/6) {
                        r = -1530*x/w + 510;
                    }

                    if(x >= 2*w/6 && x < 4*w/6) {
                        r = 0;
                    }

                    if(x >= 4*w/6 && x < 5*w/6) {
                        r = 1530*x/w - 1020;
                    }

                    if(x >= 5*w/6 && x <= w) {
                        r = 255;
                    }

                    this.writable_pixel_writer.setColor(x, y, Color.color(r/255, g/255, b/255));
                }
            }
        }
    }

On trouve les équations par résolution de systèmes à deux équations. Un exemple : pour trouver l'équation 1530*x/w - 1020, il a fallu résoudre le système suivant :

Première équation : r(4*w/6) = 0

Seconde équation : r(5*w/6) = 255

r étant une fonction affine.

Les valeurs 0, 255, 4*w/6, 5*w/6 et la nature affine de la fonction r sont déduites de ce schéma :

https://zestedesavoir.com/forums/sujet/6688/degrade-de-couleurs/?page=2#p119928

+0 -0

Elle est "impossible" car le nombre de couleurs n'est pas déterminable (enfin c'est évident, puisque c'est un dégradé…).

Lern-X

Si tu utilises du RBG pour définir ta couleur, tu as 255^3=16 581 375 différentes couleurs possibles. Ca m'étonnerai que tu cherches à faire des images de cette largeur, tu n'auras donc pas deux pixels côte à côte (sur une ligne) qui auront la même couleur.

Banni

Je ne comprends pas ton point 3 : on a un arrondi, je ne vois pas le problème que ça pose ni pourquoi tu voudrais calculer la largeur sur lequel l'arrondi est le même. Peut-être est-ce pour accélérer les calculs ?

Sinon pour ton point 4, effectivement on a une fonction affine par morceaux, avec 3×2 morceaux. On a trois couleurs, et pour passer d'une couleur à l'autre on fait en deux étapes (augmentation de l'une, puis diminution de l'autre). Je ne vois pas non plus ce qui pose problème. Une disjonction de cas ne suffit pas ?

Je ne comprends pas ton point 3 : on a un arrondi, je ne vois pas le problème que ça pose ni pourquoi tu voudrais calculer la largeur sur lequel l'arrondi est le même. Peut-être est-ce pour accélérer les calculs ?

De quel arrondi parles-tu ?

Sinon pour ton point 4, effectivement on a une fonction affine par morceaux, avec 3×2 morceaux. On a trois couleurs, et pour passer d'une couleur à l'autre on fait en deux étapes (augmentation de l'une, puis diminution de l'autre). Je ne vois pas non plus ce qui pose problème. Une disjonction de cas ne suffit pas ?

Trois couleurs ? Justement non, en fait voici ce que je veux obtenir :

http://fr.flossmanuals.net/processing/les-couleurs/static/Processing-Couleurs-color_spectrum-tiff-fr-old.png

C'est exactement ce que je veux obtenir, en RGB avec des couleurs saturées, et je ne vois pas comment faire =/

+0 -0
Banni

Je parle des arrondis qui vont transformer un réel de [0,1]³ en un triplet d'entiers chacun entre 0 et 255.

Oui, j'ai compris ce que tu veux obtenir. Les trois couleurs dont je parle sont rouge (R), vert (V) et bleu (B). Comme tu l'as toi-même décrit et comme c'est décrit sur wikipédia, on commence avec R et on va linéairement jusqu'à R+V, puis encore linéairement jusqu'à V. Ensuite on fait pareil pour passer de V à B, puis de B à R.

Donc pour obtenir ton application de [0,1] vers [0,1]³, on fait une disjonction en 6 cas, en séparant [0,1] en 6 intervalles. On peut faire plus simplement en factorisant les similarités avec un tableau, mais voilà. Ensuite il faut transformer le code manipulant des réels en un code manipulant des entiers, avec des arrondis où il faut.

Plutôt que chercher à savoir sur quel largeur une couleur sera, j'opterais plus pour essayer de calculer la couleur que doit avoir une colonne donnée.

À propos des transitions entre augmentation d'une composante et diminution d'une autre, à ma connaissance il n'y a pas d'autre solution que d'utiliser une condition.

Donc sur le principe, lorsque tu veux dessiner une colonne, tu regardes d'abord dans quel partie tu es (transition rouge-jaune ou transition jaune-vert ou …) et ensuite, tu as juste à faire une interpolation linéaire entre les deux couleurs.

transformer un réel de [0,1]³ en un triplet d'entiers chacun entre 0 et 255

Heum, tu n'as pas voulu dire "un triplet de [0;1]" plutôt ?

Donc pour obtenir ton application de [0,1] vers [0,1]³

Ah donc tout à l'heure tu voulais vraiment parler d'un répel, n'appartenant pas à [0,1]³ mais à [0,1] ?

En tout cas si j'ai bien compris ton [0,1] c'est soit R, soit G, soit B et on aimerait le transformer en un triplet.

Enfin je ne comprends pas trop ce que tu dis en fait =/

Plutôt que chercher à savoir sur quel largeur une couleur sera, j'opterais plus pour essayer de calculer la couleur que doit avoir une colonne donnée.

Je vois. Diviser la largeur de l'image par le nombre de colonnes (donc attribuer à toute colonne une largeur) et la colorier en calculant/déterminant la couleur. Le souci : quel est le nombre de colonnes ? On ne le connaît pas.

interpolation linéaire

Je ne sais pas ce que c'est, je vais voir ça.

Banni

transformer un réel de [0,1]³ en un triplet d'entiers chacun entre 0 et 255

Heum, tu n'as pas voulu dire "un triplet de [0;1]" plutôt ?

Ah ouais, j'ai raté ma phrase. Je voulais dire qu'on a un triplet de réels, et qu'on transforme chacun en un entier entre 0 et 255 en les multipliant par 256 et en arrondissant.

Donc pour obtenir ton application de [0,1] vers [0,1]³

Ah donc tout à l'heure tu voulais vraiment parler d'un répel, n'appartenant pas à [0,1]³ mais à [0,1] ?

En tout cas si j'ai bien compris ton [0,1] c'est soit R, soit G, soit B et on aimerait le transformer en un triplet.

Enfin je ne comprends pas trop ce que tu dis en fait =/

L'idée est de trouver une application f de [0,1] dans [0,1]³ qui va associer à chaque abscisse une couleur, pour faire ton dégradé. Si la largeur de ton image est n, le pixel d'abscisse x devra avoir comme couleur f(x/n). C'est histoire de simplifier pour raisonner plus facilement, mais ensuite on peut transformer l'algorithme de telle façon à ne plus manipuler que des entiers.

Si tu ne sais pas ce qu'est une interpolation linéaire, c'est ce que tu as décrit dans ton premier post :

Enfin, j'ai remarqué qu'il n'y a qu'une seule composante à la fois qui est changée au fur et à mesure qu'un dégradé est fait : d'abord RED = 255, puis ensuite on modifie UNIQUEMENT GREEN (en l'augmentant), puis on modifie UNIQUEMENT RED (en le baissant), etc.

(linéairement, ça veut dire que la vitesse est constante)

Donc mon conseil, c'est que tu essaie déjà d'écrire un algorithme qui manipule des réels.

+0 -0

Oui j'avais lu mais n'avais pas fait le rapprochement :o…

Alors par contre pourquoi donnes-tu à f l'abscisse x/n ?

Sinon le corps de f, d'après Berdes, doit absolument contenir des conditions non ? Des conditions du genre "si l'abscisse est comprise entre 0 et y, alors la couleur sera celle de départ (le rouge 255 0 0) + le vert 0 1 0", reste à déterminer y (donc la largeur de la colonne =/) (et au passage, je ne sais même pas popurquoi il est plus pertinent de choisir 0 1 0 plutôt que, par exemple, 0 50 0)

Banni

Alors par contre pourquoi donnes-tu à f l’abscisse x/n ?

Les pixels ont des abscisses entre 0 et n. On veut rétrécir le tout pour se ramener entre 0 et 1, donc on divise par n. Mais peut-être que tu ne trouves pas ça naturel.

Sinon le corps de f, d’après Berdes, doit absolument contenir des conditions non ? Des conditions du genre "si l’abscisse est comprise entre 0 et y, alors la couleur sera celle de départ (le rouge 255 0 0) + le vert 0 1 0", reste à déterminer y (donc la largeur de la colonne =/) (et au passage, je ne sais même pas popurquoi il est plus pertinent de choisir 0 1 0 plutôt que, par exemple, 0 50 0)

Je ne comprends pas ce qu’est « le vert 0 1 0 ». Tu n’as pas besoin de déterminer la largeur d’une colonne : il te suffit de savoir, pour une abscisse donnée, quelle est la couleur à lui associer. Qu’il y ait plusieurs abscisses avec la même couleur n’est pas important.


Tu peux aussi faire trois fonctions : une pour le rouge, une pour le vert, et une pour le bleu. Regardes sur un dessin comment varient ces quantités en fonction de l’abscisse. À toi de voir l’approche que tu préfères. On peut aussi utiliser des nombres rationnels au lieu de modifier le code pour ne manipuler que des entiers.


Peut-être que pour commencer, tu pourrais faire un truc plus simple : un dégradé noir → blanc sur toute la largeur de l’image. Puis faire un dégradé rouge → jaune, puis rouge → jaune → vert, puis etc.

+0 -0

Les pixels ont des abscisses entre 0 et n. On veut rétrécir le tout pour se ramener entre 0 et 1, donc on divise par n. Mais peut-être que tu ne trouves pas ça naturel.

Ah si pas de souci ! :)

Je ne comprends pas ce qu'est « le vert 0 1 0 »

Je parlais du vert RGB(0;1;0) avec les composantes R et B nulles en fait.

Tu n'as pas besoin de déterminer la largeur d'une colonne : il te suffit de savoir, pour une abscisse donnée, quelle est la couleur à lui associer. Qu'il y ait plusieurs abscisses avec la même couleur n'est pas important.

D'acc, on oublie cette notion de colonnes. Du coup il faut trouver la relation qui existe entre l'abscisse et la couleur. A mon avis il va falloir prêter une attention toute particulière à l'abscisse maximale, qui permettra de faire une "mise à l'échelle" de la distribution des couleurs. En effet, l'abscisse maximale a toujours la couleur la plus rose. Enfin voilà clairement elle a un rôle prépondérant dans la répartition des couleurs, ie. dans la fonction qui associe à une abscisse une couleur donnée (excepté pour l'abscisse minimale, qui elle est toujours du rouge) et pour elle-même (abscisse max).

Je pense qu'en me ramenant entre [0;1], comme tu me l'as conseillé, je trouverais un algo satisfaisant. Le souci c'est qu'il y a aura une grosse perte de précision non ?

Banni

Le souci c'est qu'il y a aura une grosse perte de précision non ?

Oui, et alors là tu as deux choix : sois tu utilises des nombres rationnels, soit tu transformes ton algorithme afin de n'utiliser que des nombres entiers.

Par exemple, à la place d'effectuer le test x/n ≤ 1/2, tu effectue le test 2x ≤ n.

edit : Je suis peut-être pas très bon pour expliquer après, j'aurais peut-être dû laisser répondre quelqu'un de meilleur que moi…

+0 -0

à la place d'effectuer le test x/n ≤ 1/2, tu effectue le test 2x ≤ n.

Pourquoi utiliser 1/2 comme borne ? C'est juste pour l'exemple ? En effet si je comprends bien, l'idée est d'associer aux abscisses <= 1/2 une couleur plutôt rouge-orange non ? Et ça en ferait beaucoup.

Pourquoi ne pas plutôt utiliser un pourcentage ? En se basant sur l'image qui va suivre, on pourrait dire que 5% des pixels à gauche sont rouges, 5% de ceux qui sont juste à droite sont oranges et ainsi de suite (en se basant sur les abscisses).

Banni

Oui, c'était juste un exemple.

En se basant sur l'image qui va suivre, on pourrait dire que 5% des pixels à gauche sont rouges, 5% de ceux qui sont juste à droite sont oranges et ainsi de suite (en se basant sur les abscisses).

Si tu fais ça, on va avoir une coupure entre le rouge et l'orange.

Vois-tu déjà comment faire un dégradé noir → blanc sur une largeur de n pixels ?

Bon, je suppose qu'un exemple sera plus efficace.

Supposons que tu veuilles créer une image de largeur 250 pixels. Tu sais déjà qu'il y a 6 parties dans ton image: rouge->jaune, jaune->vert, vert->cyan, cyan->bleu, bleu->violet, violet->rouge.

Mettons que tu veuilles déterminer la couleur du pixel à la colonne 105. $150/250 = 0.6$ et $3/6 \leq 0.6 \leq 4/6$, donc ton pixel est dans la 4ème partie de l'image (cyan->bleu). Maintenant, entre 0.5 et 0.6666, 0.6 est à 60%. Ce qui veut dire que ton pixel est à 40% cyan et à 60% bleu. À partir de là, tu en déduis les composantes RGB.

Il te suffit d'appliquer ce raisonnement à chaque colonne et tu pourras dessiner l'image complète.

+0 -0

Si tu fais ça, on va avoir une coupure entre le rouge et l'orange.

Yep mais je pensais augmenter progressivement (par un pallier qu'il aurait fallu déterminer) la composante G, de façon à effacer cette coupure. M'enfin ça aurait été bien compliqué.

Vois-tu déjà comment faire un dégradé noir → blanc sur une largeur de n pixels ?

Alors je pense qu'il faut partir d'un RGB(255;255;255) et décrémenter ça toutes les y abscisses, et ce y doit être choisi de telle sorte que le dégradé se fasse sur toute la largeur.

Je suis peut-être têtu :p mais pour moi ça revient à déterminer le nombre de colonnes à peindre =/

@Berdes :

Bein je ne comprends pas pourquoi on peut affirmer qu'il y a 6 parties dans l'image, alors que celles-ci sont définies par des couleurs, et que ces couleurs ne peuvent pas être utilisées comme bornes : en effet, qu'est-ce qui est considéré comme rouge, comme orange, comme jaune ? A un moment ça devient flou quoi…

+0 -0

Les 6 parties sont définies par les 5 discontinuités que tu as dans ta fonction coordonnée->couleur. Si tu regarde cette image prise sur Wikipedia:

Découpage d'un dégradé RGB

Tu peux observer indépendamment les fonctions rouge, vert et bleu. Tu as des discontinuités à 60°, 120°, 180°, 240° et 300°, d'où les 6 parties du dégradée.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte