Programación de efectos en imágenes y vídeos en Processing

Índice
- Introducción
- Objetivos
- 1.Imágenes en Processing
- 2.Transformaciones puntuales
- 3.Transformaciones espaciales lineales
- 3.1.Identidad
- 3.2.Negativo
- 3.3.Suavización
- 3.4.Contornos
- 4.Transformaciones espaciales no lineales
- 4.1.Erosión
- 4.2.Dilatación
- 4.3.Apertura y cierre
- 5.Transformaciones geométricas
- 5.1.Zoom y diezmado
- 5.2.Traslación
- 5.3.Rotación
- 5.4.Composición de transformaciones
- 6.Programación de efectos en vídeos en Processing
- Actividades
- Bibliografía
Introducción
Objetivos
-
Introducir la programación de las transformaciones puntuales, espaciales lineales, espaciales no lineales y geométricas.
-
Explorar las posibilidades del lenguaje Processing en cuanto a estas programaciones.
-
Relacionar, mediante experimentos dirigidos, los conceptos introducidos con la transformación de imágenes.
1.Imágenes en Processing
1.1.Carga y visualización de imágenes en Processing
/** * Ejemplo 1: Carga y visualización de una imagen * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 */ // Declaramos un objeto de tipo PImage PImage img; void setup() { // Asignamos a la ventana de trabajo las mismas medidas que la imagen size(696,696); // Cargamos la imagen img = loadImage("geranidolor.jpg"); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { //La función image() permite visualizar la imagen en la ventana de la aplicación image(img,0,0); }
PImage img;
img = loadImage("geranidolor.jpg");
image(img,0,0);

1.2.Imágenes y píxeles
![Figura 2. Relación entre la cuadrícula de píxeles y el array pixels[].](https://materials.campus.uoc.edu/daisy/Materials/PID_00258145/html5/img/17067_m5_002.gif)
/** * Ejemplo 2: Imágenes y píxeles (I) * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos un objeto de tipo PImage PImage img; void setup() { // Asignamos a la ventana de trabajo las mismas medidas que la imagen size(696, 696); // Cargamos la imagen img = loadImage("geranidolor.jpg"); // Siempre hemos de llamar a esta función antes de acceder al array de píxeles img.loadPixels(); } void draw() { //La función image() permite visualizar la imagen image(img, 0, 0); } void mousePressed() { // La variable loc sirve para "localizar" el píxel seleccionado dentro // del array de píxeles int loc = mouseX + mouseY * img.width; // Extraemos el color del píxel color c = img.pixels[loc]; // Estas funciones permiten consultar las componentes R, G y B de un color float r = red(c); float g = green(c); float b = blue(c); // Finalmente, imprimimos el resultado en la ventana de la Console println("El valor RGB del píxel (" + mouseX + ", " + mouseY + ") es (" + r + ", " + g + ", " + b + ")"); }
img.loadPixels();
int loc = mouseX + mouseY * img.width;
// Extraemos el color del píxel color c = img.pixels[loc]; // Estas funciones permiten consultar las componentes R, G y B de un color float r = red(c); float g = green(c); float b = blue(c);
// Estas funciones permiten consultar las componentes R, G y B de un color float r = img.pixels[loc] >> 16 & 0xFF; float g = img.pixels[loc] >> 8 & 0xFF; float b = img.pixels[loc] & 0xFF;
/** * Ejemplo 3: Imágenes y píxeles (II) * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos dos objetos de tipo PImage, uno para la imagen original // y otro para la imagen filtrada PImage imgOriginal; PImage imgFilter; void setup() { // Cargamos la imagen imgOriginal = loadImage("geranidolor.jpg"); // Creamos una nueva imagen con las mismas dimensiones que la imagen original imgFilter = createImage(imgOriginal.width, imgOriginal.height, RGB); // Asignamos a la ventana de trabajo las mismas medidas que la imagen surface.setSize(imgOriginal.width, imgOriginal.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Como siempre, hemos de llamar a estas funciones antes de acceder al array // de píxeles de las imágenes imgOriginal.loadPixels(); imgFilter.loadPixels(); int loc= 0; // Recorremos todos los píxeles de la imagen while (loc < imgOriginal.pixels.length) { // Estas funciones permiten consultar las componentes R, G y B de un color float r = imgOriginal.pixels[loc] >> 16 & 0xFF; float g = imgOriginal.pixels[loc] >> 8 & 0xFF; float b = imgOriginal.pixels[loc] & 0xFF; // En la imagen filtrada solo importamos el valor del nivel R (rojo) // y los otros dos los dejamos con nivel 0 imgFilter.pixels[loc] = color(r, 0, 0); loc++; } // Si hacemos modificaciones sobre los píxeles, siempre hemos de actualizar el array // de píxeles con la función updatePixels() imgFilter.updatePixels(); // La función image() permite visualizar la imagen filtrada image(imgFilter, 0, 0); // Guardamos el resultado en la carpeta "data" del proyecto imgFilter.save(dataPath("geranidolor2.jpg")); }
PImage imgOriginal; PImage imgFilter;
imgFilter = createImage(imgOriginal.width, imgOriginal.height, RGB);
imgFilter.pixels[loc] = color(r, 0, 0);
imgFilter.updatePixels();
imgFilter.save(dataPath("geranidolor2.jpg"));
imgFilter.save(dataPath("geranidolor2"));
surface.setSize(imgOriginal.width, imgOriginal.height);
size(imgOriginal.width, imgOriginal.height);

1.3.El método filter() de PImage
img.filter(filterName, parametre);
img.filter(GRAY);
img.filter(THRESHOLD, 0.3);
-
THRESHOLD: es la transformación de binarización, donde el valor del umbral va de 0.0 (0) a 1.0 (255). Este método necesita parámetro.
-
GRAY: convierte una imagen en color a escala de grises. No necesita parámetro.
-
OPAQUE: hace completamente opaca una imagen. No necesita parámetro.
-
INVERT: es la transformación en negativo. No necesita parámetro.
-
POSTERIZE: limita el número de colores de cada canal. El valor del parámetro establece este límite, y puede variar entre 2 y 255.
-
BLUR: aplica un filtro de tipo Guassianblur, con el radio especificado en el segundo parámetro. Si no se incluye el segundo parámetro, el valor del radio del filtro es 1. Cuanto mayor sea el radio, más acusado será el filtrado.
-
ERODE: aplica la transformación espacial no lineal erosión. No necesita parámetro.
-
DILATE: aplica la transformación espacial no lineal dilatación. No necesita parámetro.
/** * Ejemplo 4: Filtro GRAY * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos un objeto de tipo PImage PImage img; void setup() { // Cargamos la imagen img = loadImage("geranidolor.jpg"); // Asignamos a la ventana de trabajo las mismas medidas que la imagen surface.setSize(img.width, img.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Aplicamos el filtro GRAY a la imagen img.filter(GRAY); //La función image() permite visualizar la imagen filtrada image(img, 0, 0); // Guardamos el resultado en la carpeta "data" del proyecto img.save(dataPath("geranidolor2.jpg")); }

/** * Ejemplo 5: Filtro POSTERIZE * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos un objeto de tipo PImage PImage img; void setup() { // Cargamos la imagen img = loadImage("geranidolor.jpg"); // Asignamos a la ventana de trabajo las mismas medidas que la imagen surface.setSize(img.width, img.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Aplicamos el filtro POSTERIZE a la imagen img.filter(POSTERIZE, 6); //La función image() permite visualizar la imagen filtrada image(img, 0, 0); // Guardamos el resultado en la carpeta "data" del proyecto img.save(dataPath("geranidolor2.jpg")); }

2.Transformaciones puntuales
2.1.Identidad
/** * Ejemplo 6: Transformación Puntual Identidad, * para imágenes en escala de grises * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos dos objetos de tipo PImage, uno para la imagen original // y otro para la imagen filtrada PImage imgOriginal; PImage imgFilter; void setup() { // Cargamos la imagen imgOriginal = loadImage("4.1.02.png"); // Creamos una nueva imagen con las mismas dimensiones que // la imagen original imgFilter = createImage(imgOriginal.width, imgOriginal.height, RGB); // Las medidas de la ventana de trabajo permitirán visualizar // las dos imágenes a la vez surface.setSize(2*imgOriginal.width, imgOriginal.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Como siempre, hemos de llamar a estas funciones antes de acceder al // array de píxeles de las imágenes imgOriginal.loadPixels(); imgFilter.loadPixels(); int loc= 0; // Recorremos todos los píxeles de la imagen while (loc < imgOriginal.pixels.length) { // Al ser una imagen en escala de grises, R = G = B // Así que tenemos suficiente consultando uno de los canales RGB float b = imgOriginal.pixels[loc] & 0xFF; // Algoritmo - Transformación Puntual (Identidad) imgFilter.pixels[loc] = color(b); loc++; } // Si hacemos modificaciones sobre los píxeles, siempre hemos de actualizar // el array con la función updatePixels() imgFilter.updatePixels(); // La función image() permite visualizar las dos imágenes image(imgOriginal, 0, 0); image(imgFilter, imgOriginal.width, 0); // Guardamos la imagen transformada en la carpeta "data" del proyecto imgFilter.save(dataPath("imgFilter.png")); }
surface.setSize(2*imgOriginal.width, imgOriginal.height);
float b = imgOriginal.pixels[loc] & 0xFF;
imgFilter.pixels[loc] = color(b);

2.2.Negativo
// Algoritmo - Transformación Puntual (Negativo) imgFilter.pixels[loc] = color(255-b);

2.3.Binarización
// Declaramos dos objetos de tipo PImage, uno para la imagen original // y otro para la imagen filtrada PImage imgOriginal; PImage imgFilter; // Umbral int llindarValue = 20;
// Algoritmo - Transformación Puntual (Binarización) if (b < llindarValue) { imgFilter.pixels[loc] = color(0); } else { imgFilter.pixels[loc] = color(255); }

2.4.Transformaciones de aclaramiento y oscurecimiento de la imagen

// Con estos valores, definimos la forma de la curva de aclaramiento y oscurecimiento int x0 = 23; int x1 = 250; int y0 = 65; int y1 = 240;
// Algoritmo - Transformación Puntual (Aclaramiento y Oscurecimiento) if (b < x0 ) { imgFilter.pixels[loc] = color(int(map(b, 0, x0, 0, y0))); } elseif ( b < x1 ) { imgFilter.pixels[loc] = color(int(map(b, x0, x1, y0, y1))); } else { imgFilter.pixels[loc] = color(int(map(b, x1, 255, y1, 255))); }
/** * Ejemplo 9: Transformación Puntual Aclaramiento y Oscurecimiento por partes, * para imágenes en escala de grises * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos dos objetos de tipo PImage, uno para la imagen original // y otro para la imagen filtrada PImage imgOriginal; PImage imgFilter; // Con estos valores, definimos la forma de la curva de aclaramiento y oscurecimiento int x0 = 23; int x1 = 250; int y0 = 65; int y1 = 240; void setup() { // Cargamos la imagen imgOriginal = loadImage("4.1.02.png"); // Creamos una nueva imagen con las mismas dimensiones que la imagen original imgFilter = createImage(imgOriginal.width, imgOriginal.height, RGB); // Las medidas de la ventana de trabajo permitirán visualizar // las dos imágenes a la vez surface.setSize(2*imgOriginal.width, imgOriginal.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Como siempre, hemos de llamar a estas funciones antes de acceder al // array de píxeles de las imágenes imgOriginal.loadPixels(); imgFilter.loadPixels(); int loc= 0; // Recorremos todos los píxeles de la imagen while (loc < imgOriginal.pixels.length) { // Al ser una imagen en escala de grises, R = G = B // Así que tenemos suficiente consultando uno de los canales RGB float b = imgOriginal.pixels[loc] & 0xFF; // Algoritmo - Transformación Puntual (Aclaramiento y Oscurecimiento) if ( b < x0 ) { imgFilter.pixels[loc] = color(int(map(b, 0, x0, 0, y0))); } elseif ( b < x1 ) { imgFilter.pixels[loc] = color(int(map(b, x0, x1, y0, y1))); } else { imgFilter.pixels[loc] = color(int(map(b, x1, 255, y1, 255))); } loc++; } // Si hacemos modificaciones sobre los píxeles, siempre hemos de actualizar // el array con la función updatePixels() imgFilter.updatePixels(); // La función image() permite visualizar las dos imágenes image(imgOriginal, 0, 0); image(imgFilter, imgOriginal.width, 0); // Guardamos el resultado en la carpeta "data" del proyecto imgFilter.save(dataPath("imgFilter.png")); }

3.Transformaciones espaciales lineales
// Recorremos todos los píxeles de la imagen while (loc < imgOriginal.pixels.length) {
// Recorremos todos los píxeles de la imagen for (int x = 0; x < imgOriginal.width; x++) { for (int y = 0; y < imgOriginal.height; y++) {
int loc = x + y * imgOriginal.width;
3.1.Identidad
/** * Ejemplo 10: Transformación espacial lineal Identidad, *para imágenes en escala de grises * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos dos objetos de tipo PImage, uno para la imagen original // y otro para la imagen filtrada PImage imgOriginal; PImage imgFilter; // Máscara de convolución (Identidad) expresada como matriz float[][] matrix = { { 0, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 } }; // Dimensión de la máscara de convolución int matrixsize = 3; // Corrección desplazamiento int offset = 0; void setup() { // Cargamos la imagen imgOriginal = loadImage("4.2.06.png"); // Creamos una nueva imagen con las mismas dimensiones que la imagen original imgFilter = createImage(imgOriginal.width, imgOriginal.height, RGB); // Las medidas de la ventana de trabajo permitirán visualizar // las dos a la vez surface.setSize(2*imgOriginal.width, imgOriginal.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Como siempre, hemos de llamar a estas funciones antes de acceder al // array de píxeles de las imágenes imgOriginal.loadPixels(); imgFilter.loadPixels(); // Recorremos todos los píxeles de la imagen for (int x = 0; x < imgOriginal.width; x++) { for (int y = 0; y < imgOriginal.height; y++) { // Cálculo de la convolución espacial int c = convolution(x, y, matrix, matrixsize, offset, imgOriginal); // Generamos un nuevo píxel en la imagen filtrada int loc = x + y * imgOriginal.width; imgFilter.pixels[loc] = color(c); } } // Si hacemos modificaciones sobre los píxeles, siempre hemos de actualizar // el array con la función updatePixels() imgFilter.updatePixels(); // La función image() permite visualizar las dos imágenes image(imgOriginal, 0, 0); image(imgFilter, imgOriginal.width, 0); // Guardamos el resultado en la carpeta "data" del proyecto imgFilter.save(dataPath("imgFilter.png")); } // Función que calcula la convolución espacial int convolution(int x, int y, float[][] matrix, int matrixsize, int offset, PImage img) { float result = 0.0; int half = matrixsize / 2; // Recorremos la matriz de convolución for (int i = 0; j < matrixsize; i++) { for (int j = 0; i < matrixsize; j++) { // Cálculo del píxel sobre el que estamos trabajando int xloc = x + i - half; int yloc = y + j - half; int loc = xloc + img.width * yloc; // Nos aseguramos de que tomamos un píxel dentro del rango válido. En este caso estamos // aplicando la replicación de valores de píxeles próximos por localizaciones de píxeles // que salen de la imagen loc = constrain(loc, 0, img.pixels.length-1); // Cálculo de la operación convolución // Consultamos el valor del canal blue (B) result += ((imgOriginal.pixels[loc] & 0xFF) * matrix[i][j]); } } // Aplicamos el desplazamiento result += offset; // Nos aseguramosde de que el nivel de gris está en el rango (0, 255) result = constrain(result, 0, 255); // Retornamos el nivel de gris return (int)result; }
// Máscara de convolución (Identidad) expresada como matriz float[][] matrix = { { 0, 0, 0 }, { 0, 1, 0 }, { 0, 0, 0 } }; // Dimensión de la máscara de convolución int matrixsize = 3; // Corrección desplazamiento int offset = 0;
for (int x = 0; x < imgOriginal.width; x++) { for (int y = 0; y < imgOriginal.height; y++) {
int c = convolution(x, y, matrix, matrixsize, offset, imgOriginal);
int loc = x + y * imgOriginal.width; imgFilter.pixels[loc] = color(c);
int convolution(int x, int y, float[][] matrix, int matrixsize, int offset, PImage img)

3.2.Negativo
// Máscara de convolución Negativo expresada como matriz float[][] matrix = { { 0, 0, 0 }, { 0, -1, 0 }, { 0, 0, 0 } }; // Dimensión de la máscara de convolución int matrixsize = 3; // Corrección desplazamiento int offset = 255;

3.3.Suavización
// Máscara de convolución Suavización, expresada como matriz float[][] matrix = { { 1/9f, 1/9f, 1/9f }, { 1/9f, 1/9f, 1/9f }, { 1/9f, 1/9f, 1/9f } }; // Dimensión de la máscara de convolución int matrixsize = 3; // Corrección desplazamiento int offset = 0;

3.4.Contornos
// Máscara de convolución Contornos (detección) expresada como matriz float[][] matrix = { { -1, -1, -1 }, { -1, 8, -1 }, { -1, -1, -1 } }; // Dimensión de la máscara de convolución int matrixsize = 3; // Corrección desplazamiento int offset = 128;

// Máscara de convolución Contornos (realce) expresada como matriz float[][] matrix = { { -1, -1, -1 }, { -1, 9, -1 }, { -1, -1, -1 } }; // Dimensión de la máscara de convolución int matrixsize = 3; // Corrección desplazamiento int offset = 0;

4.Transformaciones espaciales no lineales
4.1.Erosión
/** * Ejemplo 15: Transformación espacial no lineal Erosión * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos un objeto de tipo PImage PImage img; void setup() { // Cargamos la imagen img = loadImage("faces.png"); // Las medidas de la ventana de trabajo permitirán visualizar // la imagen original y la imagen filtrada surface.setSize(2*img.width, img.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Visualizaremos la imagen antes de filtrar image(img, 0, 0); // Aplicamos el filtro, con el método Erosión img.filter(ERODE); // Visualizamos la imagen después de filtrar image(img, img.width, 0); // Guardamos el resultado de la transformación en la carpeta "data" del proyecto img.save(dataPath("imgFilter2.png")); }

4.2.Dilatación
// Aplicamos el filtro, con el método Dilatación img.filter(DILATE);

4.3.Apertura y cierre
/** * Ejemplo 17: Transformación espacial no lineal Obertura * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos un objeto de tipo PImage PImage img; void setup() { // Cargamos la imagen img = loadImage("faces.png"); // Las medidas de la ventana de trabajo permitirán visualizar // la imagen original y la imagen filtrada surface.setSize(2*img.width, img.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Visualizaremos la imagen antes de filtrar image(img, 0, 0); // Aplicamos el filtro, con el método Erosión img.filter(ERODE); // Aplicamos el filtro, con el método Dilatación img.filter(DILATE); // Visualizamos la imagen después de filtrar image(img, img.width, 0); // Guardamos el resultado de la transformación en la carpeta "data" del proyecto img.save(dataPath("imgFilter2.png")); }

// Aplicamos el filtro, con el método Dilatación img.filter(DILATE); // Aplicamos el filtro, con el método Erosión img.filter(ERODE);

5.Transformaciones geométricas
5.1.Zoom y diezmado
/** * Ejemplo 19: Transformación geométrica Zoom y Diezmado * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos un objeto de tipo PImage PImage img; // Para valores > 1 aplicamos un zoom, valores < 1 un diezmado float resizeValue = 1.5; void setup() { // Cargamos la imagen img = loadImage("4.1.04.png"); // Las medidas de la ventana de trabajo han de permitir visualizar // la imagen original y la imagen transformada surface.setSize(int((resizeValue+1)*img.width), int(max(resizeValue,1)*img.height)); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Visualizamos la imagen antes de ampliar image(img, 0, 0); // Aplicamos la transformación geométrica "resize" img.resize(int(resizeValue*img.width), int(resizeValue*img.height)); // Visualizamos la imagen después de aplicarle la transformación image(img, img.width/resizeValue, 0); // Guardamos el resultado de la transformación en la carpeta "data" del proyecto img.save(dataPath("imgFilter2.png")); }

float resizeValue = 0.5;

/** * Ejemplo 20: Transformación Scale * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos un objeto de tipo PImage PImage img; // Valor de la escala float scaleValue = 0.5; void setup() { // Cargamos la imagen img = loadImage("4.1.04.png"); // Medidas de la ventana de trabajo surface.setSize(int(scaleValue*img.width), int(scaleValue*img.height)); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Modifica las dimensiones del sistema de coordenadas, pero no modifica // las dimensiones de la imagen scale(scaleValue); // Visualizamos la imagen image(img, 0, 0); // Guardamos la imagen en la carpeta "data" del proyecto img.save(dataPath("img2.png")); }
5.2.Traslación
/** * Ejemplo 21: Transformación Translación * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos un objeto de tipo PImage PImage img; // Coordenadas del nuevo origen int coorX = 40; int coorY = 40; void setup() { // Cargamos la imagen img = loadImage("4.1.04.png"); // Medidas de la ventana de trabajo surface.setSize(img.width, img.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Movemos el sistema de coordenadas translate(coorX, coorY); // Visualizamos la imagen image(img, 0, 0); // Guardamos el contenido de la ventana de la aplicación como imagen // en la carpeta "data" del proyecto save(dataPath("img2.png")); }

// Medidas de la ventana de trabajo surface.setSize(img.width+ coorX, img.height+ coorY);
img.save(dataPath("img2.png"));
save(dataPath("img2.png"));
img.save(dataPath("img2.png"));
filter(GRAY);
img.save(dataPath("img2.png"));
5.3.Rotación
/** * Ejemplo 22: Transformación Rotación * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos un objeto de tipo PImage PImage img; // Valor de la rotación float rotateValue = PI/10; void setup() { // Cargamos la imagen img = loadImage("4.1.04.png"); // Medidas de la ventana de trabajo surface.setSize(img.width, img.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Rotamos el sistema de coordenadas rotate(rotateValue); // Visualizamos la imagen image(img, 0, 0); // Guardamos el contenido de la ventana de la aplicación como imagen // en la carpeta "data" del proyecto save(dataPath("img2.png")); }

5.4.Composición de transformaciones
/** * Ejemplo 23: Composición de Transformaciones (I) * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos un objeto de tipo PImage PImage img; // Valor de la escala float scaleValue = 0.5; // Coordenadas del nuevo origen int coorX = 200; int coorY = 100; // Valor de la rotación float rotateValue = PI/10; void setup() { // Cargamos la imagen img = loadImage("4.1.04.png"); // Medidas de la ventana de trabajo surface.setSize(img.width, img.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Modifica las dimensiones del sistema de coordenadas, pero no modifica // las dimensiones de la imagen scale(scaleValue); // Movemos el sistema de coordenadas translate(coorX, coorY); // Rotamos el sistema de coordenadas rotate(rotateValue); // Visualizamos la imagen image(img, 0, 0); // Guardamos el contenido de la ventana de la aplicación como imagen // en la carpeta "data" del proyecto save(dataPath("img2.png")); }

/** * Ejemplo 24: Composición de Transformaciones (II) * Francesc Martí, martifrancesc@uoc.edu, 15-04-2016 * */ // Declaramos un objeto de tipo PImage PImage img; // Valor de la escala float scaleValue = 0.5; // Coordenadas del nuevo origen int coorX = 200; int coorY = 100; // Valor de la rotación float rotateValue = PI/10; void setup() { // Cargamos la imagen img = loadImage("4.1.04.png"); // Medidas de la ventana de trabajo surface.setSize(img.width, img.height); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Esta transformación afecta a las dos imágenes que visualizaremos scale(scaleValue); pushMatrix(); // Movemos el sistema de coordenadas translate(coorX, coorY); // Rotamos el sistema de coordenadas rotate(rotateValue); // Visualizamos la imagen image(img, 0, 0); popMatrix(); // Visualizamos otra vez la imagen image(img, 0, 0); // Guardamos el contenido de la ventana de la aplicación como imagen // en la carpeta "data" del proyecto save(dataPath("img2.png")); }
6.Programación de efectos en vídeos en Processing
6.1.Aplicación de efectos en secuencias de imágenes


/** * Ejemplo 25: Transformación Puntual Negativo, por imágenes en color. * El efecto se aplicará a todas las imágenes que se encuentren en la carpeta seleccionada * y se guardarán en una nueva carpeta. * Este programa no muestra las imágenes en la ventana de la aplicación. * * Francesc Martí, martifrancesc@uoc.edu, 08-04-2018 * */ // La variable originalFolder contiene el nombre del directorio donde se encuentran las imágenes originales. // La variable filterFolder contiene el nombre del directorio donde se guardarán las imágenes filtradas. // Los dos directorios tienen que estar dentro de la carpeta del proyecto de Processing. StringoriginalFolder = "Original_Files"; StringfilterFolder = "Filtered_Files"; voidsetup() { // Medidas de la ventana de trabajo size (800, 260); background(0); noSmooth(); // Configuración de la fuente del texto textSize(12); fill(255, 255, 0); // Información en la ventana de la aplicación texto("Filtrando todas las imágenes con extensión *.png contenidas en el directorio", 10, 50); texto(sketchPath("") + originalFolder, 10, 68); texto("Las imágenes se están guardando en el directorio", 10, 100); texto(sketchPath("") + filterFolder, 10, 118); texto("Consultar la ventana de la consola para ver los detalles sobre el proceso de filtraje...", 10, 150); // La función draw() se ejecutará solo una vez noLoop(); } void draw() { // Este código permite hacer una lista con todos los archivos que se encuentran en la carpeta de las imágenes originales File dir = new Hile(sketchPath("") + originalFolder); File[] listOfFiles = decir.listFiles(); if (listOfFiles != null) { for (File aFile : listOfFiles) { // Para cada elemento encontrado dentro del directorio, si es una imagen png, ejecutamos el filtro // y la guardamos en el directorio con las imágenes filtradas if (aFile.isFile() &&afile.getName().endsWith(".png") ) { // Información en la ventana de la consola println("Filtrando la imagen " + aFile.getName()); // Declaramos dos objetos de tipos PImage, uno por la imagen original // y otro por la imagen filtrada PImageimgOriginal; PImageimgFilter; // Cargamos la imagen original imgOriginal = loadImage(sketchPath("") + originalFolder + "/" + aFile.getName()); // Creamos una nueva imagen con las mismas dimensiones que la imagen original imgFilter = createImage(imgOriginal.width, imgOriginal.height, RGB); // Carga de los píxeles de las imágenes imgOriginal.loadPixels(); imgFilter.loadPixels(); intloc= 0; // Recorremos todos los píxeles de la imagen original while (loc<imgOriginal.pixels.length) { // Estas funciones permiten consultar las componentes R, G y B de un color float r = imgOriginal.pixels[loc] >> 16 & 0xFF; float g = imgOriginal.pixels[loc] >> 8 & 0xFF; float b = imgOriginal.pixels[loc] & 0xFF; // Algoritmo - Transformación Puntual (Negativo) imgFilter.pixels[loc] = color(255-r, 255-g, 255-b); loc++; } // Si hacemos modificaciones sobre los píxeles, siempre tenemos que actualizar // el array con la función updatePixels() imgFilter.updatePixels(); // Guardamos la imagen transformada en su carpeta imgFilter.save(sketchPath("") + filterFolder + "/" + aFile.getName()); } } } // Todas las imágenes han sido filtradas texto("Proceso de filtraje finalizado.", 10, 168); }



6.2.La librería Video de Processing
/** * Ejemplo 26: Reproducción de un vídeo en modo "loop" * * Francesc Martí, martifrancesc@uoc.edu, 09-04-2018 * */ // Importamos la librería Video import processing.video.*; Movie myMovie; voidsetup() { size(1280, 720); // Cargamos el fichero de vídeo myMovie = new Movie(this, "Traffic.mp4"); // Reproducimos el fichero de vídeo en modo "loop" myMovie.loop(); } void draw() { // Visualizamos los fotogramas en la ventana de la aplicación image(myMovie, 0, 0); } // Esta función es llamada cada vez que un nuevo fotograma está disponible para leer voidmovieEvent(Movie m) { m.read(); }
void draw() { myMovie.filter(INVERT); image(myMovie, 0, 0); saveFrame("Filtered_Files/frame-####.png"); }
/** * Ejemplo 27: Filtro INVERT sobre un archivo de vídeo. * El programa aplica el efecto sobre los fotogramas del vídeo * y genera una secuencia de imágenes. * * Francesc Martí, martifrancesc@uoc.edu, 09-04-2018 * */ // Importamos la librería Video import processing.video.*; Movie myMovie; // Sirve para numerar las imágenes de la secuencia de imágenes. intcont =0; voidsetup() { size(1280, 720); // Cargamos el fichero de vídeo myMovie = new Movie(this, "Traffic.mp4"); // Reproducimos el fichero de vídeo myMovie.play(); } void draw() { // Visualizamos los fotogramas en la ventana de la aplicación image(myMovie, 0, 0); } // Esta función es llamada cada vez que un nuevo fotograma está disponible para leer voidmovieEvent(Movie m) { m.read(); // Aplicamos un filtro de tipo INVERT al fotograma que vamos a visualizar // En este ejemplo usamos un filtro de tipo INVERT, pero se podría // implementar cualquiera de los efectos vistos durante el módulo myMovie.filter(INVERT); // Guardamos en el disco duro el fotograma actual filtrado myMovie.save(sketchPath("")+ "Filtered_Files/test" + nf(cont, 3) + ".png"); cont++; }
Actividades

