jardínBit

Imágenes: Capas y máscaras

1 Capas con PGraphics

La clase PGraphics funciona para crear “lienzos virtuales” o capas en los que podemos dibujar.

Estas capas se pueden comportar como imágenes PImage: se dibujan con la función image( ) y se pueden modificar con métodos como .resize( ) o .filter( ).

Por cada capa necesitamos una variable:

PGraphics capa;

En la función setup() la inicializamos con un tamaño:

capa = createGraphics( 640, 480 );

Para dibujar en ella podemos utilizar cualquier función de las que ya conocemos, pero ahora como métodos de la capa. Hay que preceder el dibujo con .beginDraw() y terminarlo con .endDraw():

// dibuja en la capa:
capa.beginDraw();
capa.background(0); // fondo negro
capa.fill(255); // relleno blanco
capa.ellipse( 320, 240, 100, 100);
capa.endDraw();

Posteriormente podemos dibujar la capa en la función draw() con image( ) :

// dibuja la capa
image( capa, 0, 0);

1.1 Ejemplo: Figuras con blur

En este ejemplo dibujamos unos círculos en una capa, y luego utilizamos el método .filter( ) para aplicar un desenfoque.

// declara variable de tipo "PGraphics"
PGraphics capa1;
void setup(){
 size( 640, 480 ); 
 // crea la capa
 capa1 = createGraphics(640, 480);
 // dibuja en la capa
 capa1.beginDraw();
 capa1.background( 0 );
 capa1.fill( 255 );
 capa1.ellipse(100, 100, 100, 100);
 capa1.fill(0);
 capa1.ellipse(100, 100, 80, 80);
 capa1.fill(255);
 capa1.ellipse(100, 100, 40, 40);
 capa1.endDraw();
 // podemos aplicar un filtro como si la capa fuera PImage
 capa1.filter( BLUR, 3);
}

void draw(){
  // dibujamos la capa en el canvas como si fuera PImage
 image( capa1, 0, 0);
}

2 Capas como Máscaras

Podemos utilizar las capas dibujadas con PGraphics como máscaras del canal alpha de una imagen, aprovechando el método .mask( ) de PImage.

La imagen o capa que utilicemos como máscara ha de estar en escala de grises, y se va a utilizar como canal alpha de la imagen enmascarada.

Los pixeles donde la máscara tenga un valor de 0 (color negro) se harán completamente transparente, los pixeles donde la máscara tenga un valor de 255 (color blanco) serán completamente opacos, y cualquier valor intermedio tendrá una transparencia correspondiente.

2.1 Ejemplos de máscaras

2.1.1 Máscara generada programáticamente

En este ejemplo usamos un ciclo for para generar una máscara que consiste en franjas blancas y negras alternadas.

Esta máscara la aplicamos sobre la imagen original.

En el fondo se dibuja una copia de la imagen que fue obtenida y filtrada previamente.

PImage foto; // imagen original
PImage fotoInvertida; // imagen invertida
PGraphics capa1; // capa

void setup() {
  size( 640, 480 );
  // crear "objeto" de tipo PImage
  foto = loadImage("trajinera.jpg");
  foto.resize( width, height );

  // copiar foto
  fotoInvertida = foto.get();
  fotoInvertida.filter( INVERT ); // invierte foto

  // crea capa para la máscara:
  capa1 = createGraphics( 640, 480);
  
   // dibuja máscara:
  capa1.beginDraw();
  capa1.background(0);
  capa1.fill(255);
  // dibuja múltiples franjas rectangulares
  for (int i=0; i<=640; i+=40) {
    capa1.rect(i, 0, 20, 480);
  }
  capa1.endDraw();

  // enmascara la imagen
  foto.mask( capa1 );
}

void draw() {
  background(255);

  // dibuja la imagen invertida de fondo
  image(fotoInvertida, 0, 0);
  
  // dibuja la imagen enmascarada,
  // sus áreas transparentes dejarán ver el fondo
  image(foto, 0, 0);

  // con esta función podemos ver el aspecto de la máscara
  //image( capa1, 0, 0);
}

2.1.2 Máscara interactiva

Podemos aprovechar el ciclo de animación para redibujar la máscara en cada frame.

En este ejemplo usamos una estructura similar al anterior, con la diferencia de que la máscara se dibuja dentro de la función draw() y los círculos en ella dependen de las variables mouseX y mouseY.

PImage foto; // foto original
PImage fotoInvertida; // foto invertida
PGraphics capa1;

void setup(){
  size( 640, 480 );

  // crear "objeto" de tipo PImage
  foto = loadImage("trajinera.jpg");
  foto.resize( width, height );

  // copiar foto
  fotoInvertida = foto.get();
  fotoInvertida.filter( INVERT ); // invierte foto

  // crea capa para la máscara:
  capa1 = createGraphics( 640, 480);
}

void draw(){
  // dibuja máscara en cada frame, 
  // utilizando coords mouseX, mouseY como centro de círculos
  capa1.beginDraw();
  capa1.background(0); // negro
  capa1.fill(255); // blanco
  capa1.ellipse(mouseX, mouseY, 300, 300);
  capa1.fill(0); // negro
  capa1.ellipse(mouseX, mouseY, 200, 200);
  capa1.fill(255); // blanco
  capa1.ellipse(mouseX, mouseY, 100, 100);
  capa1.endDraw();

  // enmascara la imagen
  foto.mask( capa1 );
  
  // dibuja la foto invertida de fondo
  image(fotoInvertida, 0, 0);

  // dibuja encima la foto original enmascarada
  image(foto, 0, 0);
}

3 Capas para organizar el dibujo

En ocasiones queremos aprovechar el comportamiento de “dibujar sin borrar el fondo” en conjunto con otros comportamientos.

Dibujar en capas nos puede ayudar, como muestra este ejemplo.

Aquí se dibuja en una capa con un “pincel” obtenido como recorte de una imagen. Esta capa se dibuja encima de la imagen filtrada.

// Pincel a base de recorte
// El trayecto se dibuja sobre una "capa".
// Esto permite dibujar un fondo
PImage foto;
PImage recorte;
PGraphics capa;

void setup(){
  size( 640, 480 );
  // crear "objeto" de tipo PImage
  foto = loadImage("trajinera.jpg");
  foto.resize( width, height );
  
  // obtén un recorte de la foto a color
  recorte = foto.get(300, 300,    100, 100);
 
  // filtra a la foto original (el recorte no se afecta)
  foto.filter( GRAY );
  
  // crea la capa del tamaño del lienzo
  capa = createGraphics( 640, 480);
}

void draw(){
  // actualiza la capa con el pincel
  capa.beginDraw();
  capa.image( recorte, mouseX, mouseY);
  capa.endDraw();

  // dibuja la foto
  image( foto, 0, 0);
  // dibuja la capa encima
  image( capa, 0, 0);
}