Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

BitmapData.threshold : Démystification

Compatible ActionScript 3. Cliquer pour en savoir plus sur les compatibilités.Par billyben (Billyben), le 16 novembre 2012

Bonjour ! Dans ces quelques lignes, point question de parcourir toutes les possibilités qu'offre cette fabuleuse méthode threshold, mais juste quelque notes pour commencer à la prendre en main…

Cette méthode (aka fonction) de la classe BitmapData permet de manipuler les pixels d'une image, plus précisément les couleurs de ces pixels, selon certaines conditions (toujours sur la couleur de ces fameux pixels).

Prérequis Vouloir travailler sur les Bitmap et donc forcément les BitmapData !

Bitmap - BitmapData

Un petit mot très rapide sur ces deux objets.

  • Bitmap : Il s'agit de l'objet d'affichage qui va permettre d'afficher (…) une image
  • BitmapData : Cet objet contient toutes les informations sur les pixels d'une image. Il permet de manipuler ces données. C'est donc cet objet que l'on va utiliser pour manipuler des pixels…

La Couleur

Comme la méthode threshold permet de manipuler la couleur d'un pixel, et bien parlons z'en un p'tit peu tout même.
La couleur est représenté par un entier (Integer - int), positif ! Donc, dans notre langage préféré, elle est représentée par un objet “uint”. Je ne parlerai donc dans la suite que d'entier, et il est fort probable qu'il traine encore quelques “int” au lieu de “uint” dans les code que je vais vous présenter, ne vous en formalisez pas pour autant…
Donc la couleur est un entier, soit le rouge-rouge est donc :

16711680

… bref vu comme ça, ça ne parle pas trop, voire c'est carrément obscur. Il existe une notation beaucoup plus claire (toute mesure gardée) : la notation hexadécimale, soit en base 16 (0 à 9 puis A à F ensuite, pour faire court). Notre rouge s'écrira alors (pour nous):

0xFF0000

Nous avons ici une couleur “16 bits”, contenant les informations sur les canaux RVB / Rouge – Vert –Bleu (RGB pour les anglicistes) :
Impression
Cependant, pour utiliser cette méthode threshold, nous avons besoin de couleurs “32 bits”, soit avec l'information sur le canal Alpha (transparence), soit ARVB (ou ARGB) :
Impression
Chaque canal (A – R – V – B) allant de 0 à 255 (….) soit de 00 à FF.

Threshold

Nous y voilà !!
Donc cette méthode manipule les informations de couleur d'une image. Attention, cette méthode traite chaque pixel indépendamment, soit pixel par pixel.

Elle permet de modifier les pixels d'une image de destination (en fait du BitmapData correspondant) par des pixels d'une image source (un autre BitmapData) selon un test sur la couleur, effectué sur les pixels de l'image source. L'image source pouvant être l'image de destination……..

  • * Par la suite, et par abus de langage, j'utiliserai le terme “image” à la place de BitmapData
  • * Dans la plupart des exemples montrés, l'image de destination est une image “vierge” afin de bien mettre en avant les effets de la méthode threshold

Utilité

Il existe beaucoup de moyens pour aller jouer avec les pixels d'une image via notre langage préféré.
Par exemple, pour remplacer une couleur par une autre, nous pouvons parcourir à l'aide de 2 boucles (sur la largeur et la hauteur) le tableau de pixels, tester la couleur et, si elle correspond à celle voulue, zou on la remplace, sinon on garde.
Ceci correspond à la fonction basique de la méthode threshold.

Mais voilà, ceci peut être très lent, et la méthode threshold est suffisamment optimisée pour qu'on ne puisse pas obtenir les mêmes résultats “à la main”.
Pour vous en convaincre, voici un petit test qui compare ces deux méthodes (boucles vs threshold), en remplaçant la couleur cible choisie dans l'image, ceci 100 fois :

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

Chez moi j'ai un ratio de près de 50 entre les 2 méthodes sur ces 100 itérations!!

La méthode et ses arguments

Voici la syntaxes pour la méthode threshold :

public function threshold(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, operation:String, threshold:uint, color:uint = 0, mask:uint = 0xFFFFFFFF, copySource:Boolean = false):uint

Elle s'écrit donc :

destinationBitmapData.threshold(sourceBitmapData, sourceRect, destPoint, operation, threshold, color, mask, copySource)


Les arguments (que nous détaillerons par la suite) :

  • sourceBitmapData:BitmapData — L’image bitmap d'entrée à utiliser (! attention, l'entrée est bien un objet BitmapData et non Bitmap [NDLR]!). L'image source peut être un autre objet BitmapData ou faire référence à l'occurrence de BitmapData actuelle.
  • sourceRect:Rectangle — Rectangle qui définit la zone de l'image source à utiliser en tant qu'entrée.
  • destPoint:Point — Point de l'image de destination (l'occurrence de BitmapData actuelle) correspondant au coin supérieur gauche du rectangle source.
  • operation:String — L'un des opérateurs de comparaison suivants, transmis en tant que chaîne : ”<”, ”⇐”, ”>”, ”>=”, ”==”, ”!=”
  • threshold:uint — Valeur par rapport à laquelle chaque pixel est testé afin de déterminer s'il est inférieur ou égal au seuil ou s'il le dépasse.
  • color:uint (default = 0) — Valeur de couleur sur laquelle un pixel est réglé si le test de seuil aboutit. La valeur par défaut est 0×00000000.
  • mask:uint (default = 0xFFFFFFFF) — Masque à utiliser pour isoler un composant de couleur.
  • copySource:Boolean (default = false) — Si la valeur est true, les valeurs de pixels de l'image source sont copiées vers la destination lorsque le test de seuil échoue. Si la valeur est false, l'image source n'est pas copiée lorsque le test de seuil échoue.


Notons également que la fonction retourne le nombre de pixels qui ont été modifiés, ce qui peux être très pratique (par exemple savoir rapidement si notre image contient des pixels vides, transparents, rouge….).

Les arguments threshold, color et opération

  • threshold : comme son nom ne l'indique pas, représente la couleur dans l'image originale à tester.
  • color : la couleur de remplacement pour les pixels qui satisferont au test sur la couleur “threshold” (argument ici, pas la fonction ! franchement, ils auraient pu trouver un autre nom pour cet argument !)
  • opération : l'opération “mathématique” qui va être utilisée pour le test, elle peut être (6 possibilités ):
    • ”==“ ou ”!=“ : égale à ou différente de
    • ”>“ ou ”>=“ : supérieure ou supérieure ou égale
    • ”<“ ou ”⇐“ : inférieure ou inférieure ou égale à

Bref, si nous renseignons :

  • threshold = 0x FF FF 00 00
  • color = 0x FF 00 00 FF
  • operation = ”==”

La fonction revient à dire :

“Je remplace tous les pixels dont la couleur est égale (”==”) à rouge (0xFFFF0000 – non transparent !) par du bleu (0xFF0000FF – toujours non transparent)”


Voici un exemple pour tester ces 3 arguments. Cliquez sur une des couleurs de l'image source pour l'utiliser en tant qu'argument “threshold” (couleur de test), sélectionnez avec le colorPicker la couleur de remplacement, et avec le slider la transparence de celle-ci.

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

Les arguments sourceRect et destPoint

  • sourceRect : il s'agit d'un rectangle (au sens Object Rectangle) qui définit la partie de l'image source à traiter. Aucun des pixels en dehors de ce rectangle ne sera pris en compte. Ce rectangle possède des coordonnées (x et y), une largeur et une hauteur.

Notez bien que les coordonnées doivent être relatives à celles de l'image !

  • destPoint : il s'agit d'un point (Object Point ) qui définit les coordonnées dans l'image de destination qui figureront le point d'origine du rectangle précédant. Les autres pixels de l'image de destination, hors rectangle de destination, ne seront pas affectés.

Par exemple :

  • sourceRect : x=12, y=54, width=50, height=25
  • destPoint : x=48, y=22

Ceci revient à dire :

“Le résultat de la méthode threshold concernant les pixels de l'image source contenus dans le rectangle en x=12 et y=54, de largeur 50 et de hauteur 25 sera (le résultat!) transféré dans l'image de destination dans le rectangle en x=48 et y=22, de largeur 50 et de hauteur 25. ”


Un petit exemple pour illustrer la chose. Vous pouvez déplacer le rectangle sur l'image source, il définit le Rectangle “sourceRect” pour la méthode threshold. Vous pouvez également déplacer la cible sur l'image de destination, pour déterminer le destPoint, le carré vert figurant les dimensions de l'image de destination.

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu. Oui, je sais, j'ai bâclé la gestion des drag…..

Les arguments sourceBitmapData et copySource

  • sourceBitmapData : Il s'agit de l'image source (BitmapData), sur laquelle va être effectué le test sur les pixels à destination de l'image de destination.
  • copySource : Il s'agit d'un booléen (VRAI/FAUX) qui permet :
    • si VRAI : tous les pixels de l'image source (une fois “modifiée” par le threshold) seront copiés vers l'image de destination
    • si FAUX : seuls les pixels ayant été “modifiés” (satisfaisant au test) seront copiés vers l'image de destination.

Il s'agit de paramètres importants, qui peuvent totalement modifier le rendu.

Notez que si la source est l'image de destination, alors le paramètre copySource n'aura aucun impact (puisque les pixels qui n'auront pas été modifiés sont déjà présents dans l'image). Sauf si vous utilisez les argument “sourceRect” et “destPoint” avec des coordonnées d'origine différentes (x et y différents)!



L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

L'argument mask

Voici venue la douloureuse… !!
De loin le plus obscur et le plus difficile à prendre en main. A tel point que je ne me risquerai pas à quelques explications que ce soit, simplement une vue très simplifiée de la chose.

Mask, comme son nom l'indique, est un masque. Masque de bits il s'entend (!Aië!). Son fonctionnement est pervers donc je ne l'utilise qu'en tant que “selecteur”, selecteur de canal (A-R-V-B) pour effectuer le test….
Bref, un pitit exemple textuel vaut mieux que de longues inexplications :

  • Si j'ai un threshold (l'argument !!) à 0x FF 00 FF 1E
  • Un mask à 0×00 00 FF 00
  • Et un pixel d'une couleur 0xAE 9C FF 00
  • Avec une opération ”==”

Le test :

  • thresold == couleurPixel
  • ne sera pas 0x FF 00 FF 1E == 0xAE 9C FF 00
  • mais 0x 00 00 FF 00 == 0x 00 00 FF 00

Nous avons sélectionné via le mask le canal Vert !!
Ici, tous les pixels qui contiennent du vert (à fond : FF / 255) passeront le test de la méthode.
Vous pouvez combiner des sélections sur différents canaux, mais là s'arrête ma compréhension de la chose…

Un exemple tout de même :

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

Un exemple d'utilisation

Des Trucs


L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

  • Détourage
    • Dans l'image source je supprime les couleurs ”>=” à 0xFF EF EF EF (vers le blanc) avec le threshold, sur un mask 0xFF 00 FF 00 (l'image ne contenant pas de vert).
    • Puis je dessine cette source modifiée dans l'image de destination (méthode “draw”).
  • Contour :
    • Dans l'image de destination je thresholde la source sur les pixel ”⇐” 0xFF 77 77 77 vers le noir, avec un copySource à FAUX.
  • Ombre chinoise
    • Dans l'image de destination je thresholde la source sur les pixels ”<” à 0xFF CC CC CC (vers les blancs), avec une couleur à 0xFF 55 55 55 avec un copySource à FAUX, et un mask à 0xFF 00 FF 00 (les verts, car hormis le blanc, l'image source ne contient pas de vert).
  • Juste le rouge : ici 3 threshold d'affilé :
    • Dans l'image source je supprime les blancs (cf Détourage 1).
    • Toujours dans l'image source je supprime les noirs.
    • Dans l'image de destination je thresholde la source modifiée sur les pixels rouges (threshold à 0xFF 6A 00 00 et mask à 0xFF FF 00 00)


  • Sans le rouge :
    • Dans l'image source je supprime pixel avec une composante rouge (threshold : 0xFF 6A 00 00 et mask à 0xFF FF 00 00).
    • Puis je dessine cette source modifiée dans l'image de destination (méthode “draw”)
  • Sans le perso :
    • Dans l'image source je supprime les blancs (cf Détourage 1).
    • Dans l'image source je supprime les Noirs (opération ”⇐”, thresold : 0xFF 77 77 77).


Remplir des formes fermées

Voici quelque chose que j'ai utilisé récemment, et qui m'a sorti de la panade !
Alors évidemment, ça a ses limites, mais ça m'a parfaitement convenu dans le contexte, et ça tourne sans problème sur la frame (bon, ça doit dépendre de la taille de l'image me direz vous).
Donc l'exemple :

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

Les sources