Forums Développement Multimédia

Aller au contenu

Palettemap()

palettemap as3 bitmap pixel couleur CODE Actionscript

34 réponses à ce sujet

#1 Kainry

    Ceinture Orange

  • Members
  • PipPipPip
  • 46 messages

Posté 28 November 2012 - 16:37 PM

Bonjour à tous,

Pour ceux qui avait déjà vue mon ancien post sur la duplication d'un tableau provenant d'une classe, je suis toujours dans le même projet, juste une étape plus éloigner.
Sinon pour les autres je vais brièvement résumer la partie du projet sur laquelle je bloque.

J'importe une image dans un bitmap que j'ai créer. (donc l'image s'affiche dans le bitmap et on distingue bien les pixels)... Jusque là tous va bien.

Cependant maintenant je souhaiterais pouvoir modifier tous les pixels de cette image pour qu'ils soient d'une couleur correspondante à ma palette.

J'ai beau cherché je ne trouve pas de réel exemple sur l'utilisation de la fonction palettemap(), en tous cas rien de très précis.

Car je sais que pour la fonction palettemap() nous créons par la suite 4 tableaux (redArray, greenArray, blueArray, alphaArray) mais ma question est qu'est ce qui vient apparaître dans ces tableaux. (oui c'est surement bête mais je suis perdu...)

Est ce que dans ces tableaux doivent y être inscrit uniquement la valeur de R pour le redArray, G pour le greenArray etc...

Et peut être que c'est pas du tous possible avec cette fonction.

Désolé je n'ai pas de code disponible pour le moment mais se soir j'essaierais de vous poster un petit test effectuer.

Merci d'avance.

#2 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 28 November 2012 - 20:39 PM

Bonsoir Kainry,

Content de voir que tu avances. Et... je comprends très bien ta question :mrgreen: ;-)

Voici comment je comprends la documentation de cette fonction:
Si tu veux, par exemple, transformer les pixels de couleur ( R,V,B )=(10,20,30) en pixels de couleur (60, 50, 40) tu dois utiliser les 3 tableaux redArray, greenArray, blueArray, avec les valeurs suivantes:
redArray[10]=60
greenArray[20]=50
blueArray[30]=40
Ça c'est les valeurs pour cette couleur, mais il faut aussi que tous les redArray[de 0 à 255] soient définis. Pareil pour les 2 autres tableaux. Ça te fera 3 tableaux de 256 nombres chacun.

J'imagine que ta palette de couleur est limitée, donc que plusieurs couleurs de l'image d'origine prendront au final la même couleur. Par exemple si tous les pixels dont R=9,10 ou 11, V=19,20,21 et B=29,30,31 doivnet devenir (10,20,30) il faudra:

redArray[9]=10
redArray[10]=10
redArray[11]=10
greenArray[19]=20
greenArray[20]=20
greenArray[21]=20
blueArray[29]=30
blueArray[30]=30
blueArray[31]=30

Bon, j'espère que je ne m'avance pas trop, j'ai eu la flemme de vérifier que je comprends bien cette fonction :oops:

Ça me semble donc tout à fait possible de faire ce que tu veux avec paletteMap, par contre si tu as pas mal de couleurs dans ta palette Ça va peut-être être fastidieux de remplir les tableaux. Où alors trouver un moyen de le faire en le programmant plutôt qu'à la main...

#3 Kainry

    Ceinture Orange

  • Members
  • PipPipPip
  • 46 messages

Posté 29 November 2012 - 06:29 AM

Bonjour lilive !

Désolé pour hier soit je n'ai pas eu le temps de regarder et donc répondre au poste,

Comme toujours merci de ta réponse.

Donc si j'ai bien compris c'est ce que je pensais plus ou moins... mais je dois faire 3ligne pour chaque couleur ? (une Red une Green un Blue)?

Je ne peux pas simplement faire comme ceci :

redArray= [valeur R de la couleur 1, valeur R de la couleur 2 etc ];
greenArray = [valeur G de la couleur 1, valeur G de la couleur 2 etc];
blue Array = [valeur B de la couleur 1, valeur B de la couleur 2 etc];

Voila ce sera ma question du matin (:

#4 paodao

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 7065 messages

Posté 29 November 2012 - 10:25 AM

salut

Citation

mais je dois faire 3ligne pour chaque couleur ?
oui et non :-)

en faite c'est la même chose
faire
tab = [1,2,3];
ou
tab[0] = 1;
tab[1] = 2;
tab[2] = 3;
est la meme chose

a+

ps: je suis pas sure d'avoir compris la question ;-)

#5 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 29 November 2012 - 10:29 AM

Tu peux remplir ton tableau comme tu veux, ce qui compte c'est de passer à la fonction des tableaux qui contiennent 256 valeurs.

var a:Array = new Array();
a[0] = 10;
a[1] = 20;
a[2] = 30;
 
Donne le même résultat que:
var a:Array = [10, 20, 30];
Et effectivement cette seconde façon de faire et beaucoup plus courte.

[edit] Moi je viens de me faire griller par paodao. Salut paodao :)

#6 paodao

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 7065 messages

Posté 29 November 2012 - 10:34 AM

salut lilive ;-)

#7 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 29 November 2012 - 10:36 AM

Mmmm…
Moi, je penserais que palettemap n'est pas adapté pour coloriser une image avec une palette.
Palettemap est plutôt adaptée aux corrections de contraste, luminosité, par ce qu'il travaille couche par couche. Il ne permet pas de travailelr par sélection d'une couleur via ses 3 couches.

Un exemple de cas simple pour essayer de montrer l'impossibilité du truc :
- tu as 4 couleurs dans ton image (sur le principe [r,v,b])
[20,20,00], [30,30,00],[00,20,20],[00,30,30]
- tu voudrais passer 1 et 2 à [20,20,00] et 3 et 4 à [00,30,30]

- tu ne peux pas modifier la valeur v parfois vers 20 et parfois vers 30 avec palettemap.


Peut être une solution du côté de threshold, mais je ne suis pas sûr…
Passer pixel par pixel, mais ça sera long… (tout dépend de l'usage)/

#8 Kainry

    Ceinture Orange

  • Members
  • PipPipPip
  • 46 messages

Posté 29 November 2012 - 10:50 AM

Merci pour vos réponse...

@paodao et lilive : merci il me semblait bien que se serait plus simple ainsi (étant donné que je possède 256 couleur)...

@dIdIer : pour le threshold il me semblait qu'il modifier tous sur une simple couleur... c'est pourquoi je suis partie sur le palettemap()

Et donc pour répondre à ta question de l'usage :
je possède une palette de 256 couleur pour laquelle j'aimerais l'affecter à n'importe qu'elle image importer dans l'application.
Il me semblait justement que palettemap() permet un "adressage" de couleur comme si par exemple : "toi qui est bleu je n'est pas ta couleur mais ta couleur se rapproche de ce bleu là donc hop je te change!

Donc se serait quelle fonction la mieux ? palettemap ou threshold ? (il se peux que j'avais pas compris cette dernière fonction ^^)

Encore merci pour vos réponse !

#9 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 29 November 2012 - 11:13 AM

PaletteMap te permets de remplacer une "nuance" du canal rouge par une autre "nuance" du canal rouge, une nuance du canal vert par une autre nuance du canal vert. Mais il n'y a pas de possibilité de "voir" la couleur complète dans cette opération.Ce n'est pas une opération par "couleur" mais par "canal".

Un jaune, composé de rouge et de vert sera mécaniquement influencé par les modifications apportées aux canaux rouge et vert.

La seule possibilité que je vois avec paletteMap va dans l'autre sens.
C'est de créer des seuils : 6 par canal, par exemple. Et ce sont ces seuils qui t'imposeront une palette.

La méthode threshold permet de remplacer des couleurs arvb par une autre couleur arvb SI elles passent un test logique. Ça, Ça pourrait permettre d'appliquer une palette de couleurs.
Mais le test logique est assez simple, je crois (je ne l'ai pas beaucoup utilisée cette fonction) et il faut avoir un bon niveau pour jongler avec les opérations binaires pour créer des masques par canaux…

#10 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 29 November 2012 - 11:17 AM

Dixit la doc :

Citation

L'utilisation de la méthode threshold() permet d'isoler et de remplacer les gammes de couleurs d'une image
Mais c'est plus facile à dire qu'a faire.

Le principe à disposition :

Citation

La logique du test de la méthode threshold() est définie comme suit :
  • Si ((pixelValue & mask) operation (threshold & mask)), définissez le pixel sur color.
  • Dans le cas contraire, si copySource == true, réglez le pixel sur la valeur de pixel correspondante dans sourceBitmap.


#11 Kainry

    Ceinture Orange

  • Members
  • PipPipPip
  • 46 messages

Posté 29 November 2012 - 11:17 AM

Donc il s'agirait d'utiliser le threshold pour modifier la couleur pixel/pixel ?
Et donc le test logique consiste en quoi? l'utilisation d'un bytearray?

désolé si je suis confus dans mes question mais là tu viens de me perdre :)

#12 Kainry

    Ceinture Orange

  • Members
  • PipPipPip
  • 46 messages

Posté 29 November 2012 - 11:18 AM

Ah attend ^^ nos dernier postes se sont croisés...

Pourquoi l'utilisation de mask?

#13 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 29 November 2012 - 11:35 AM

Pour cibler certains bits et pas d'autres…
Si ça ne te parle pas, tu peux oublier. C'est très complexe. J'ai beaucoup de mal avec ça et je ne me sens pas de pousser plus loin mes recherches. A chaque fois ça a été un chronophage monstrueux (à moins que quelqu'un de plus pointu soit dispo ?)
paletteMap et treshold sont des routines très rapides mais pas très souples, amha.

Si tu n'as pas besoin d'une rapidité foudroyante, je pense que tu devrais plutôt faire une boucle pixel à pixel, avec des tests plus traditionnels. Et au besoin, on pourra t'aider à l'optimiser.

#14 Kainry

    Ceinture Orange

  • Members
  • PipPipPip
  • 46 messages

Posté 29 November 2012 - 11:46 AM

Merci pour tes réponses,

Je vais me renseigner et voir l'utilisation du threshold de plus près !

Mais pour ta boucle pixel à pixel en français sa donnerai ça ? :

Pour le pixel n°1 si ça couleur est différente de la couleur disponible dans la palette alors changer ça couleur en fonction d'une couleur plus proche...

Si c'est bien ça, je ferais également un petit test avec cette méthode...

Encore merci du temps que tu m'accordes !

#15 paodao

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 7065 messages

Posté 29 November 2012 - 11:57 AM

yop
pour les mask c'est pas tres compliqué en faite (mais je suis pas sure d'avoir tout compris)
cela sert à ciblier les canaux que tu veux utiliser pour le test
par exemple tu as la couleur
aabbcc
tu met le mask
ffffff
cela va utiliser tous les canaux
maintenant si tu utilise le mask
ff00ff
cela ne va pas utiliser le canal vert

dans beaucoup de cas tu peux utiliser le mask 0xffffffff

a+

#16 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 29 November 2012 - 11:58 AM

NB : je ne suis pas un pro en programmation et pas forcément de bon conseil. J'ai juste l'avantage de bien connaître le monde de la couleur et de maîtriser sa logique numérique, ce qui me donne une vision particulière des questions comme la tienne. A toi de faire le tri…

Pour la boucle traditionnelle, je ferais sans doute quelque chose comme ça :
pour chaque coordonnée xy {
   couleur = couleur dans l''image
   r = canal r de la couleur
   v = canal v de la couleur
   b = canal b de la couleur
   au_plus_proche = 255*3;
   pour chaque p_couleur = couleur de la palette {
         p_r = valeur absolue de la diffférence entre r et canal r de p_couleur
         p_v = valeur absolue de la diffférence entre v et canal v de p_couleur
         p_b = valeur absolue de la diffférence entre b et canal b de p_couleur
         différence = p_r + p_v + p_b
         si différence inférieure à au_plus_proche, je mémorise p_couleur
  }
  j''applique la valeur p_couleur mémorisée au pixel (x,y)
}

Ensuite, il y aura beaucoup d'optimisations possibles si c'est trop lent, mais ça te permettra déjà de voir si le rendu est celui que tu attends.

#17 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 29 November 2012 - 12:47 PM

Et voilà, je me suis planté, désolé Kainry, ça m'apprendra à ne pas tester... :oops:
Effectivement paletteMap ne semble pas un bon candidat pour faire ça.
Heureusement que Dldler est passé par là (je l'attendais d'ailleurs, sur un tel sujet ;) )

Un autre essai possible serait peut-être d'utiliser une formule légèrement différente pour la différence?
pour chaque coordonnée xy {
   couleur = couleur dans l''image
   r = canal r de la couleur
   v = canal v de la couleur
   b = canal b de la couleur
   au_plus_proche = 255*3;
   pour chaque p_couleur = couleur de la palette {
         p_r = soustraction entre r et canal r de p_couleur
         p_v = soustraction entre v et canal v de p_couleur
         p_b = soustraction entre b et canal b de p_couleur
         différence = Math.sqrt( p_r * p_r + p_v * p_v + p_b * p_b )
         si différence inférieure à au_plus_proche, je mémorise p_couleur
  }
  j''applique la valeur p_couleur mémorisée au pixel (x,y)
}

Kainry, pour faire cela en actionscript tu auras besoin de ceci, je te le dis car je ne sais pas si tu connais:


var c:uint = unBitmapData.getPixel(x,y);        // récupére la couleur du pixel x,y
var r:int = c >> 16;                       // valeur du canal rouge de c
var v:int = (c >> 8) & 0xFF;  // valeur du canal vert de c
var b:int = c & 0xFF;                   // valeur du canal bleu de c
unBitmapData.setPixel(x, y, 0xAA8844);    // Peint le pixel x,y avec la couleur 0xAA8844

 


#18 Kainry

    Ceinture Orange

  • Members
  • PipPipPip
  • 46 messages

Posté 29 November 2012 - 12:58 PM

Un grand merci a vous tous !

Me voila plus éclairer dans ma recherche et aide à solution.

Je vais tester ça dans l'après midi si j'en ai le temps je vous tiendrais tous au courant !

@lilive par contre pourrait tu m'éclairer sur le 16, et 8 qui tu à utiliser? pourquoi ces deux nombres? les numéros des bytes correspondant à la couleur? genre le bleu de 0 à 8, le vert de 9 à 16, le rouge de 17 à 24 ? (si j'ai bien compris ^^)

Encore merci à vous 3 !

#19 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 29 November 2012 - 13:06 PM

Voir le messageKainry, le 29 November 2012 - 12:58 PM, dit :

@lilive par contre pourrait tu m'éclairer sur le 16, et 8 qui tu à utiliser? pourquoi ces deux nombres? les numéros des bytes correspondant à la couleur? genre le bleu de 0 à 8, le vert de 9 à 16, le rouge de 17 à 24 ? (si j'ai bien compris ^^)
C'est ça. Désolé je n'ai pas de lien sous la main, mais c'est un sujet sur lequel tu trouveras beaucoup de documentation et de discussion sur le net, et surement sur ce forum d'ailleurs.

#20 Kainry

    Ceinture Orange

  • Members
  • PipPipPip
  • 46 messages

Posté 29 November 2012 - 13:10 PM

ça marche ! je vous tiendrais au jus (en repostant ici le test) ^^

#21 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 29 November 2012 - 13:13 PM

Si les 2 méthodes cherchant la distance entre les couleurs de l'image et celles de la palette ne donnent pas un assez bon résultat, il y aura surement mieux à faire en comparant les couleurs sur un mode HSL plutôt que RVB. Mais c'est une autre paire de manches, et je suis presque sûr que Dldler y a pensé mais n'en a pas parlé pour ne pas compliquer d'avantage :mrgreen:
Si besoin, un article que j'ai trouvé qui peut donner des idées: http://blog.soulwire...-colour-palette

#22 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 29 November 2012 - 21:37 PM

Au fait, à propos de threshold, billyben vient d'écrire un tutoriel dessus: http://forums.mediab...pdata_threshold

#23 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 30 November 2012 - 09:50 AM

Un petit exemple.
Pour tester, il faut copier le code dans l'image 1 d'un fichier Flash.
Dans ce fichier Flash, il faut importer une image dans la bibliothèque et la partager pour ActionScript sous le nom Test.
Ne pas mettre une image trop grande, le code est lent.

J'ai créé une palette par le code. Comme elle a une logique progressive, on pourrait optimiser l'algorithme en calculant la valeur par canal plutôt que de comparer avec les couleurs de la palette, mais ça ne fonctionnera pas si ta palette est aléatoire ou provient d'une autre source d'image… A toi de voir.

J'ai commenté autant que j'ai pu, mais je n'aurai sans doute pas le temps de répondre aux questions.
Peut-être que d'autres pourront prendre le relais.


// On prépare le bitmapdata, les variables nécessaires au calcul
// et on affiche le bitmap
var bm:BitmapData = new Test(0,0);
var largeur:int = bm.width;
var hauteur:int = bm.height;
addChild(new Bitmap(bm));

// Plein de variables nécessaires aux calculs.
// Déclarées ici pour gagner du temps à l'exécution
var _rvb:uint; // Servira à stocker une couleur
var _drvb:uint; // Servira à stocker une différence entre 2 couleurs
var _rvb_proche:uint; // Servira a stocker la couleur la plus proche
var _drvb_proche:uint; // Servira à stocker la plus petite différence
var _r:uint,_v:uint,_b:uint; // Servira à stocker la valeur des canaux RVB
var _dr:int,_dv:int,_db:int; // Servira à stocker la différence par canal RVB
var i:int,j:int,k:int; // compteurs pour les boucles

// Pour la création d'une palette d'exemple
var ecart_couleur:int = 44; // Ecrat entre chaque teinte pour chaque canal
var nbre_couleurs:int; // Nombre de couleurs dans la palette
nbre_couleurs = 256 / ecart_couleur + 1;// nbre couleurs par couche
nbre_couleurs = nbre_couleurs * nbre_couleurs * nbre_couleurs + 1;// nbre couleurs total

var palette:Vector.<uint>;
palette = new Vector.<uint>(nbre_couleurs,true);
// Pour éviter de refaire des calculs,
// on stocke les décompositions par canal des couleurs de la palette
var p_r:Vector.<uint>;
var p_v:Vector.<uint>;
var p_b:Vector.<uint>;
p_r = new Vector.<uint>(nbre_couleurs,true);
p_v = new Vector.<uint>(nbre_couleurs,true);
p_b = new Vector.<uint>(nbre_couleurs,true);

// Fabrication d'une palette par intervalles
// On en profite pour stocker les valeurs r, v, b
// afin de limiter les calculs
i = 0;
for (_r=0; _r<256; _r+=ecart_couleur)
{
  for (_v=0; _v<256; _v+=ecart_couleur)
  {
   for (_b=0; _b<256; _b+=ecart_couleur)
   {
        _rvb=_r<<16|_v<<8|_b;

        palette[i]=_rvb|0xFF000000;
        p_r[i]=_r;
        p_v[i]=_v;
        p_b[i++]=_b;
   }
  }
}
// On ajoute du blanc à la palette
palette[i]=0xFFFFFFFF;
p_r[i]=p_v[i]=p_b[i]=0xFF;

/*
* CODE PRINCIPAL
*/

bm.lock(); // Accélère l'accès au bm
// On parcourre le bitmapdata
for (i=0; i<largeur; i++)
{
  for (j=0; j<hauteur; j++)
  {
   _rvb=bm.getPixel(i,j); // La couleur au point (i,j)
   // On ne travaille pas les couleurs présentes dans la palette
   if (palette.indexOf(_rvb)!=-1) break;
   // On décompose la couleur
   _r=_rvb>>16&0xFF;
   _v=_rvb>>08&0xFF;
   _b=_rvb>>00&0xFF;
   // Valeurs de départ de la plus petite différence
   // et de la couleur la plus proche
   _rvb_proche=0x000000;
   _drvb_proche=uint.MAX_VALUE;
   // Pour chaque couleur de la palette, on calcule les différences par canaux,
   for (k=0; k<nbre_couleurs; k++)
   {
        _dr=_r>p_r[k] ? _r-p_r[k] : p_r[k]-_r;
        _dv=_v>p_v[k] ? _v-p_v[k] : p_v[k]-_v;
        _db=_b>p_b[k] ? _b-p_b[k] : p_b[k]-_b;
        _drvb=_dr+_dv+_db;
        // si la différence est inférieure, on stocke les valeurs trouvées
        if (_drvb<_drvb_proche)
        {
         _drvb_proche=_drvb;
         _rvb_proche=palette[k];
        }
   }
   // On applique la couleur trouvée au pixel (i,j)
   bm.setPixel(i,j,_rvb_proche);
  }
}
bm.unlock(); // Libère l'affichage du bm


#24 Kainry

    Ceinture Orange

  • Members
  • PipPipPip
  • 46 messages

Posté 30 November 2012 - 10:18 AM

C'est super gentil !! MERCI !!

Je m'y penche cette après-midi mais après une lecture rapide les commentaires m'aideront à tous comprendre.

Encore merci

#25 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 01 December 2012 - 10:26 AM

Pour voir, j'ai repris ton code Dldler, en utilisant une comparaison de couleur basée sur les valeurs HSL plutôt que sur les valeurs RVB.
J'ai mis 3 slider qui permettent de donner un priorité plus ou moins grande aux valeurs HSL. On peut donc privilégier la ressemblance au niveau de la teinte, de la saturation, ou de la luminosité.
Voici ce que ça donne. Je suis un peu déçu, ça n'améliore pas franchement il me semble. Peut-être qu'avec une autre image et une autre palette le résultat serait plus probant?
C'est largement plus lent à l'exécution qu'en mode RVB, c'est pour cela que j'ai mis une petite case à cocher pour travailler sur une version basse résolution de l'image.

En mode RVB:


- Afficher le SWF -
Fichier joint  ReducePalette2.swf   295.23 Ko   1 téléchargement(s)




En mode HSL:


- Afficher le SWF -
Fichier joint  ReducePalette4.swf   324.01 Ko   1 téléchargement(s)




Comparaison:
Fichier joint  comparaison.png   260.74 Ko   1 téléchargement(s)




Sources:
Fichier joint  src.zip   203.08 Ko   0 téléchargement(s)

#26 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 01 December 2012 - 14:29 PM

J'étais assez dépité que la comparaison des couleurs en mode HSL ne donne pas un résultat absolument plus convaincant.
Alors j'ai cherché avec d'autres palettes de couleurs pour voir, me disant que certaines palettes seraient peut-être optimisées pour une comparaison en HSL.
Et comme je n'étais pas encore convaincu, j'ai codé un outils de comparaison des 2 méthodes, sur différentes images, avec différentes palettes.
Le voici.
Je suis toujours aussi mitigé sur la pertinence d'utiliser le HSL plutôt que le RVB :(

Mais ton sujet m'a bien intéressé comme tu vois Kainry!


[edit] Hum, le HSL peut être pas mal quand même... Je viens d'essayer avec la palette de Dldler, le curseur H à 0.1, le S encore plus bas, et le L à 1, et j'ai trouvé ça mieux que le RVB. dites-moi ce que vous en pensez si vous voulez :)

Fichier(s) joint(s)



#27 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 01 December 2012 - 20:14 PM

Un dernier pour la journée, et puis j'arrête de jouer tout seul :)
J'ai ajouté une comparaison en mode HSV.
J'ai aussi essayé de définir une autre palette, mais elle est nulle.



- Afficher le SWF -
Fichier joint  ReducePalette8.swf   1.74 Mo   1 téléchargement(s)

Fichier joint  src.zip   1.1 Mo   1 téléchargement(s)

#28 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 03 December 2012 - 09:10 AM

:-) Hello lilive.

Désolé de te laisser jouer tout seul. Je ne peux plus faire de Flash chez moi. Même pas acceder aux forums… :-(
Du coup, il me reste les pauses au boulot et le midi en semaine pour participer.

La comparaison est en effet assez difficile, surtout parce que les images sont très petites.
De mon côté, j'ai optimisé et accéléré les calculs, mais sans doute en perdant encore un peu de qualité. Par contre, ça devrait t'aider à faire des tests viables sur des images plus grandes.
Et puis c'est un bon exemple de la façon d'utiliser le threshold pour limiter les calculs.

Je nettoie le code et je commente avant de poster. Je vous dépose ça à 14h si c'est prêt.

#29 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 03 December 2012 - 14:00 PM

Me re-voilà.
Le code est assez ésotérique, même commenté.
Une 'certaine' maîtrise du binaire est recommandée (pour comprendre ce qui se passe).
Sinon, vous pouvez l'utiliser sans forcément tout comprendre, en modifiant la palette selon vos envies (voir les versions de lilive et je regarde à construire une palette 6x6x4 via du code)
Et vous pouvez changer la qualité de la conversion en modifiant la propriété 'arrondi'.
Elle correspond a la suppression du nombre de bits correspondants.
Soit :
- arrondi 4 : les bits 1,2,3,4 en partant de la droite ne sont pas pris en compte
La valeur peut donc aller de 1 à 7 en théorie.
Dans la pratique on est limité par le temps de traitement selon la puissance de la machine.

Tout ça accélère les calculs et je peux maintenant traiter une image 800x600 sur mon vieux poste en arrondi 5
Je pourrai donner quelques précisions s'il y a des questions.

var i:int,j:int;// Compteurs pour les boucles
var _r:uint,_v:uint,_b:uint;// Compteurs pour les boucles RVB

// On prépare le bitmapdata et on affiche le bitmap
var bm:BitmapData = new Test(0,0);
var rectangle:Rectangle = bm.rect;
var OO:Point = new Point();
addChild(new Bitmap(bm));

// Gestion de la précision au niveau du bit : on prépare les masques binaires
var arrondi:uint = 5;// Ici, les 5 bits de droite (faibles) seront inutilisés et donc masqués lors des calculs
var _arrondi:uint = 1 << arrondi;
var masque_arrondi:uint = 0xFF << 24 | (_arrondi - 1) << 16 | (_arrondi - 1) << 8 | (_arrondi - 1);// Les bits arvb utiles
masque_arrondi =  ~  masque_arrondi; // Le masque des inutiles

// Plein de variables nécessaires au calculs des différences
// Déclarées ici pour gagner du temps à l'exécution
var _rvb:uint;// Servira à stocker une couleur
var _rvb_proche:uint;// Servira a stocker la couleur la plus proche
var _difference_rvb:uint;// Servira à stocker une différence entre 2 couleurs
var _difference_rvb_proche:uint;// Servira à stocker la plus petite différence
var _difference_r:Vector.<uint>;// Servira a stocker les pré_calculs de différences
var _difference_v:Vector.<uint>;// Servira a stocker les pré_calculs de différences
var _difference_b:Vector.<uint>;// Servira a stocker les pré_calculs de différences

// Création d'une palette d'exemple
var palette:Vector.<uint>;// Vecteur des valeurs uint des couleurs de la palette
var nombre_de__couleurs:int;// Nombre de couleurs dans la palette
var ecart_couleur:int = 44;// Ecart entre chaque teinte pour chaque canal
nombre_de__couleurs = 0x100 / ecart_couleur + 1;// nbre couleurs par couche
nombre_de__couleurs = nombre_de__couleurs * nombre_de__couleurs * nombre_de__couleurs + 1;// nbre couleurs total
palette = new Vector.<uint>(nombre_de__couleurs,true);
// On fabrique la palette par ajout de l'écart sur les canaux rvb
i = 0;
for (_r=0; _r<0x100; _r+=ecart_couleur)
{
  for (_v=0; _v<0x100; _v+=ecart_couleur)
  {
   for (_b=0; _b<0x100; _b+=ecart_couleur)
   {
        palette[i++]=0xFF<<24|_r<<16|_v<<8|_b;
   }
  }
}
// On impose le blanc dans la palette
palette[i]=0xFFFFFFFF;

// Pour éviter de refaire des calculs de différences,
// on les stocke dans un tableau 2 dimensions permettant d'obtenir :
// differences_pour[a][b] = valeur absolue de la différerence entre a et b
// (a et b pouvant varier de 0 à 0xFF)
var differences_pour:Vector.<Vector.<uint>>=new Vector.<Vector.<uint>>(0x100,true);
for (i=0; i<0x100; i++)
{
  differences_pour[i]=new Vector.<uint>(0x100,true);
  for (j=0; j<0x100; j++)
  {
   differences_pour[i][j]=i<j?j-i:i-j;
  }
}


/*
* code principal
*/

// Le principe est de parcourir la gamme de toutes les couleurs possibles,
// mais en utilisant l'arrondi pour incrémenter les canaux rvb
// L'arrondi est masqué par le threshold, ce qui lui permet de traiter
// en un seul passage toutes les couleurs avec une précision au bits non masqués par l'arrondi
// NB : ça fonctionne parce que l'arrondi est un nombre ne comprenant que des 1 en binaire !

for (_r=0; _r<0x100; _r+=_arrondi)
{
  // On charge les différences précalculées pour r
  _difference_r=differences_pour[_r];

  for (_v=0; _v<0x100; _v+=_arrondi)
  {
   // On charge les différences précalculées pour v
   _difference_v=differences_pour[_v];
 
   for (_b=0; _b<0x100; _b+=_arrondi)
   {
        // On charge les différences précalculées pour b
        _difference_b=differences_pour[_b];
 
        // Valeurs de départ de la plus petite différence et de la couleur la plus proche
        _rvb_proche = _difference_rvb_proche = uint.MAX_VALUE;
 
        // Pour chaque couleur de la palette, on calcule les différences par canaux,
        // si la différence est inférieure, on stocke les valeurs trouvées
        for each (_rvb in palette)
        {
         _difference_rvb=_difference_r[_rvb>>16&0xFF]+_difference_v[_rvb>>8&0xFF]+_difference_b[_rvb&0xFF];
         if (_difference_rvb<_difference_rvb_proche)
         {
          _difference_rvb_proche=_difference_rvb;
          _rvb_proche=_rvb;
         }
        }
        // On applique la couleur à tout ce qui est proche, en masquant les bits inutiles
        bm.threshold(bm,rectangle,OO,"==",_r<<16|_v<<8|_b,_rvb_proche,masque_arrondi);
   }
  }
}
bm.unlock();// Libère l'affichage du bm
 


#30 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 03 December 2012 - 20:19 PM

Ah, il est revenu! :mrgreen:

Bonne idée que tu as eue.
Fais-je erreur en conjecturant que son inconvénient est qu'on ne peut pas bien focaliser la précision sur des endroits de la gamme de couleur? (par exemple on ne peut décider d'avoir une palette plus fournie pour les couleurs saturées?)

Il faudrait l'inclure à mon application de comparaison des méthodes.



Si j'ai bien compris le projet de Kainry, ce n'est pas grave si les images ne sont pas grandes, puisqu'il se dirige vers du graphisme pixel art (cf ici), d'où mon parti pris de réduire les images puis les re-agrandir pour obtenir la pixelisation.

Et de mon côté j'ai eu une autre idée pour simplement réduire les couleurs à une palette 8x8x4:


var ct:ColorTransform = new ColorTransform(8 / 256, 8 / 256, 4 / 256, 1);
destBD.draw(sourceBD, null, ct);
// les canaux de couleurs sont maintenant dans l'intervale [0..7][0..7][0..3]

ct = new ColorTransform(255 / 7, 255 / 7, 255 / 3, 1);
destBD.draw(destBD, null, ct);
// les canaux de couleurs repassent dans l'intervale [0..255][0..255][0..128]

 

Du coup c'est très rapide. Mais on ne peux absolument rien paramétrer, la palette de sortie est imposée.

Le hic c'est que ça ne marche pas comme ça, tout le bleu disparait, ça doit être une incompréhension de ma part de la mécanique interne du ColorTransform.
Je m'en suis sorti comme ça:


var ct:ColorTransform = new ColorTransform(8 / 256, 8 / 256, 4 / 256, 1);
destBD.draw(sourceBD, null, ct);

// les canaux de couleurs sont maintenant dans l'intervale [0..7][0..7][0..3]

ct = new ColorTransform(255.01 / 7, 255.01 / 7, 128.01 / 3, 1);
destBD.draw(destBD, null, ct);
// les canaux de couleurs sont maintenant dans l'intervale [0..255][0..255][0..128]

ct = new ColorTransform(1, 1,  255.01 / 128, 1);
destBD.draw(destBD, null, ct);
// les canaux de couleurs repassent dans l'intervale [0..255][0..255][0..255]
 

Voici mon application de test incluant ce nouveau mode de calcul:



- Afficher le SWF -
Fichier joint  ReducePalette10.swf   1.74 Mo   2 téléchargement(s)

Fichier joint  src.zip   1.11 Mo   1 téléchargement(s)

#31 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 04 December 2012 - 14:25 PM

Un peu en retard, mais voilà la construction de la palette 8x8x4

var palette:Vector.<uint>=new Vector.<uint>();
var i:Number = 0;
var r:Number,v:Number,b:Number;
var intervalle_couleur:Number = 0x100/7; // NB : 8 couleurs =7 intervalles
for (r=0; r<0x100; r+=intervalle_couleur)
{
  for (v=0; v<0x100; v+=intervalle_couleur)
  {
   for (b=0; b<0x100; b+=intervalle_couleur+intervalle_couleur)
   {
        palette[i++]=r<<16|v<<8|b;
   }
  }
}


// Affichage
i=0;
for each (var rvb:uint in palette)
{
  graphics.beginFill(rvb);
  graphics.drawRect(int(i/8)*10,i++%8*10,8,8);
  graphics.endFill();
}

Pour le reste, je n'ai pas trop le temps, désolé.
Mais bubulle m'a l'air très bien :-)

Fichier(s) joint(s)



#32 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 04 December 2012 - 19:40 PM

Coucou,
Je ne crois pas que tu l'aies vu, mais dans mon code j'ai fait aussi une 8x8x4.
Je m'y suis pris comme ça:

var r:int, v:int, b:int;            
i = 0;
for (var rr:int = 0; rr < 8; rr ++) {
    for (var vv:int = 0; vv < 8; vv ++) {
        for (var bb:int = 0; bb < 4; bb ++) {
           
            r = Math.round(rr / 7 * 255);
            v = Math.round(vv / 7 * 255);
            b = Math.round(bb / 3 * 255);
            rvb = r << 16 | v << 8 | b;
            setPaletteColor(rvb, i);
            i++;
           
        }
    }
}
Le résultat est différent du tien, on a la même chose sur les canaux rouge et vert, mais pas sur le bleu.
Ton bleu prend les valeurs: 0, 73, 146, 219
Le mien les valeurs: 0, 85, 170, 255

Comment ça marche les opérateurs de décalage sur des Number? ça convertit d'abord en int?
Je viens de lire que l'opérateur de décalage converti bien le nombre en int avant de faire l'opération, donc la différence ne vient pas de là.

#33 dldler

  • Community Manager
  • PipPipPipPipPipPipPipPip
  • 4163 messages

Posté 05 December 2012 - 09:58 AM

Grosse erreur logique de ma part :)
La différence vient de la :

// NB : 8 couleurs =7 intervalles

Alors évidemment, on ne peut pas calculer via le double.
Puisqu'on a 4 couleurs = 3 intervalles…

Du coup, je me rends compte que mon intervalle n'était pas tout à fait juste non plus.
Voilà les 2 corrections :

var palette:Vector.<uint>=new Vector.<uint>();
var i:Number = 0;
var r:Number,v:Number,b:Number;
var intervalle_RV:Number = 0xFF/7; // NB : 8 couleurs = 7 intervalles
var intervalle_B:Number = 0xFF/3; // NB : 4 couleurs = 3 intervalles
for ( r = 0; r < 0x100; r += intervalle_RV )
{
   for ( v = 0; v < 0x100; v += intervalle_RV )
   {
        for ( b = 0; b < 0x100; b += intervalle_B )
        {
          palette[i++]=r<<16|v<<8|b;
        }
   }
}
trace(palette[255].toString(16));


#34 Kainry

    Ceinture Orange

  • Members
  • PipPipPip
  • 46 messages

Posté 05 December 2012 - 10:20 AM

Bonjour,

Désolé je ne commente pas trop ce qui ce passe ici mais je suis !
Je suis sur un autre problème en attendant mais je vois que vous vous amusez bien avec ce sujet :)

Encore merci pour votre aide,
Je risque de vous posez des questions quand je m'y pencherais sérieusement,
Et je vous tiendrais au courant quand j'en aurais fini avec tous ça pour que vous voyez le rendu final du projet.

Kainry.

#35 lilive

  • Moderateur
  • PipPipPipPipPipPipPipPip
  • 2993 messages

Posté 05 December 2012 - 18:52 PM

Voir le messageKainry, le 05 December 2012 - 10:20 AM, dit :

Désolé je ne commente pas trop ce qui ce passe ici mais je suis !
OK, je me demandais un peu c'est vrai. T'as bien fait de le dire ;)


Voir le messageKainry, le 05 December 2012 - 10:20 AM, dit :

je vois que vous vous amusez bien avec ce sujet :)
Carrément :mrgreen:


Voir le messageKainry, le 05 December 2012 - 10:20 AM, dit :

Et je vous tiendrais au courant quand j'en aurais fini avec tous ça pour que vous voyez le rendu final du projet.
Ah oui alors!



1 utilisateur(s) li(sen)t ce sujet

0 membre(s), 1 invité(s), 0 utilisateur(s) anonyme(s)

authorised training centre

Centre de Formation Mediabox - Adobe et Apple Authorised Training Center.

Déclaré auprès de la Direction du Travail et de la Formation Professionnelle

Mediabox : SARL au capital de 62.000€ - Numéro d'activité : 11 75 44555 75 - SIRET : 49371646800035

MEDIABOX, 23, rue de Bruxelles, 75009 PARIS

FFP