A › 17 - Images 2 : pixels

Charger les pixels

La page A › 10 a permis de voir comment afficher une image matricielle dans la fenêtre.

Pour "manipuler" directement les pixels composant une image, deux fonctions supplémentaires sont nécessaires :

  • loadPixels() : crée le tableau pixels[] qui contient les valeurs de chaque pixel de l'image affichée. La taille de ce tableau est égale au nombre de pixels de l'image, c'est à dire à width x height.
  • updatePixels() : actualise l'affichage du tableau pixels[], à utiliser notamment après modification du tableau pixels[].

Mais qu'est-ce qu'un pixel ? Dans Processing, un pixel est un élément de type color. Il s'agit du plus petit élément composant une image.

En niveaux de gris

Une image en niveaux de gris, traditionnellement appelée en "noir et blanc" est composée de pixels, définis chacun par un niveau de gris, de 0 (noir) à 255 (blanc) dans le mode par défaut. Et peut-on changer ce mode par défaut ?

La fonction brightness() permet de connaître la valeur du niveau de gris d'un pixel. Elle renvoie un nombre de type float.

Un traitement d'image consiste à modifier les pixels pour obtenir un effet précis. Chaque effet repose sur un algorithme propre. Il existe des centaines de traitements d'images habituels et certains logiciels se sont spécialisés dans ces fonctionnalités. La plupart de ces traitements reposent sur des notions mathématiques évoluées, mais quelques-uns utilisent des principes très simples et permettent de comprendre ce qui est réalisé, pixel par pixel.

• Négatif

Le principe consiste à "inverser" les niveaux de gris d'une image. Concrètement, on utilise une fonction affine qui échange les valeurs 0 et 255 : elle associe à toute valeur x comprise entre 0 et 255 le nombre 255-x. Les valeurs les plus élevées deviennent les plus faibles et inversement.

Ce qui donne par exemple :

explorer processing

image source en niveaux de gris

explorer processing

image obtenue

PImage source;

void setup() {

  size(200, 200);

  source = loadImage("zebre-nb.jpg");

  image(source, 0, 0); // affichage de l'image

  loadPixels(); // création du tableau pixels[]

  noLoop();

}

void draw() {

  for(int position = 0; position < pixels.length; position++) {

    float x= brightness(pixels[position]);

    pixels[position] = color(255 - x);

  }

  updatePixels(); // actualisation de l'image

}

• Effet de seuil

Le principe de l'effet de seuil consiste à transformer une image initiale en "niveaux de gris" en une image en "noir et blanc" au sens propre, c'est à dire dont chaque pixel est soit noir, soit blanc. On définit un seuil en choisissant une valeur comprise entre 0 et 255 : tous les pixels dont le niveau de gris est inférieur au seuil passent à 0 et ceux dont le niveau de gris est supérieur au seuil passent à 255.

Ce qui donne par exemple :

explorer processing

image source en niveaux de gris

explorer processing

image obtenue avec un seuil à 120

PImage source;

void setup() {

  size(200, 200);

  source = loadImage("zebre-nb.jpg");

  image(source, 0, 0); // affichage de l'image

  loadPixels(); // création du tableau pixels[]

  noLoop();

}

void draw() {

  float niveau = 120; // niveau à régler, de 0 à 255

  for(int position = 0; position < pixels.length; position++) {

    if(brightness(pixels[position]) > niveau) {

      pixels[position] = color(255); // blanc

    }

    else {

      pixels[position] = color(0); // noir

    }

  }

  updatePixels(); // actualisation de l'image

}

En couleurs

On peut définir un pixel en donnant ses trois composantes : les niveaux de rouge, vert et bleu. Les trois fonctions red(), green(), blue() permettent d'accéder aux composantes d'une donnée de type color, et par conséquent aux composantes d'un pixel. Elles renvoient un nombre de type float.

On peut ainsi par exemple agir sur les couleurs d'une image, sans en changer les formes et détails.

explorer processing

image source

explorer processing

image obtenue en inversant le niveau de bleu

PImage source;

void setup() {

  size(300, 200);

  source = loadImage("paysage.jpg");

  image(source, 0, 0); // affichage de l'image

  loadPixels(); // création du tableau pixels[]

  noLoop();

}

void draw() {

  for(int position = 0; position < pixels.length; position++) {

    float rouge=red(pixels[position]);

    float vert=green(pixels[position]);

    float bleu=blue(pixels[position]);

    color remplacement=color(rouge,vert,255-bleu);

    pixels[position]=remplacement;

  }

  updatePixels(); // actualisation de l'image

}

explorer processing

image obtenue en recherchant les fortes valeurs de bleu

Un autre exemple, avec recherche des fortes valeurs de bleu. Dans le programme précédent, l'instruction

    color remplacement=color(rouge,vert,255-bleu);

est remplacée par :

    color remplacement;

    if (bleu>50){

      remplacement=color(0,0,bleu);

    }

    else {

      remplacement=color(255, 255, 255);

    }