Es necesario saber cómo se muestra una imagen, para ello realizamos el siguiente código:
En donde la función preload, carga la imagen seleccionada. En el setup creamos el canvas y el botón para poner el canvas en pantalla completa. La función draw nos permite cargar la imagen. La función fullScreen no habilita la opción de la pantalla completa. La función windowResized, nos permite modifica el tamaño del canvas para que la imagen se adapte al tamaño de la ventana.
1linklet img;
2linklet button;
3link
4linkfunction preload() {
5link img = loadImage("/vc/docs/sketches/workshops/imaging/BabyYoda.jpg");
6link}
7link
8linkfunction setup() {
9linkcreateCanvas(windowWidth-15, windowHeight-21);
10linknoLoop();
11link button = createButton('FullScreen');
12link button.attribute('style','box-shadow:inset 0px 1px 0px 0px #000000;\n' +
13link '\tborder-radius:6px;\n' +
14link '\tborder:1px solid #000000;\n' +
15link '\tdisplay:inline-block;\n' +
16link '\tcursor:pointer;\n' +
17link '\tcolor:#000000;\n' +
18link '\tfont-family:Arial;\n' +
19link '\tfont-size:15px;\n' +
20link '\tfont-weight:bold;\n' +
21link '\tpadding:6px 24px;\n' +
22link '\ttext-decoration:none;\n' );
23link button.position(3, 3);
24link button.mousePressed(fullScreen);
25link}
26link
27linkfunction draw() {
28link img.resize(windowWidth, windowHeight);
29link image(img, 0, 0);
30link}
31link
32linkfunction fullScreen() {
33link let fs = fullscreen();
34link fullscreen(!fs);
35link}
36link
37linkfunction windowResized() {
38link resizeCanvas(windowWidth-15, windowHeight-21);
39link}
La única diferencia respecto a mostrar una imagen, es que sólo se modifica la función draw, en donde recorremos pixel por pixel de la imagen, y le restamos a cada valor rgb del pixel 255, con el fin de obtener el negativo.
Código:
1linkfunction draw() {
2link img.resize(windowWidth, windowHeight);
3link image(img, 0, 0);
4link let d = pixelDensity();
5link let npixels = 4 * (width * d) * (height * d);
6link loadPixels();
7link for (let i = 0; i < npixels; i += 4) {
8link pixels[i] = 255 - pixels[i];
9link pixels[i + 1] = 255 - pixels[i + 1];
10link pixels[i + 2] = 255 - pixels[i + 2];
11link }
12link updatePixels();
13link}
En fotografía digital e imágenes generadas por computadora, una escala de grises o imagen es aquella en la que el valor de cada píxel es una sola muestra que representa solo una cantidad de luz; es decir, lleva solo información de intensidad. Las imágenes en escala de grises, una especie de monocromo en blanco y negro o gris, se componen exclusivamente de tonos de gris. El contraste varía desde el negro en la intensidad más débil hasta el blanco en la más fuerte.
Las imágenes en escala de grises son distintas de las imágenes en blanco y negro de dos tonos de un bit, que, en el contexto de las imágenes por computadora, son imágenes con solo dos colores: blanco y negro (también llamadas imágenes de dos niveles o binarias). Las imágenes en escala de grises tienen muchos tonos de gris en el medio.
A continuación se realiza la descripción de 2 filtros y se muestra el resultado con una imagen.
Este es el algoritmo de escala de grises para los programadores novatos. Esta fórmula genera un razonablemente agradable equivalente en escala de grises, su simplicidad hace que sea fácil de implementar y optimizar. Sin embargo, esta fórmula no está exenta de defectos mientras rápido y sencillo, que hace un trabajo pobre de representar tonos de gris en relación con la forma en que los seres humanos perciben la luminosidad (brillo).
Para aplicarlo tomamos el RGB de cada pixel y lo dividimos entre 3, como muestra el siguiente código:
1linksImg.loadPixels();2linkfor (let i = 0; i < npixels; i += 4) {3link let gray = (img.pixels[i] + img.pixels[i + 1] + img.pixels[i + 2]) / 3;4link sImg.pixels[i] = gray;5link sImg.pixels[i + 1] = gray;6link sImg.pixels[i + 2] = gray;7link sImg.pixels[i + 3] = img.pixels[i + 3];8link}9linksImg.updatePixels();
luma representa el brillo de una imagen (la parte "blanco y negro" o acromática de la imagen). Por lo general, la luminancia se empareja con la crominancia. Luma representa la imagen acromática, mientras que los componentes cromáticos representan la información de color. Los sistemas de video pueden almacenar y transmitir información cromática a una resolución más baja, optimizando los detalles percibidos en un ancho de banda particular.
Para encontrar el Luma seguimos una serie de pasos:
Paso 1:
Convertir el pixel RGB a decimal (0.0 a 1.0) Para ello usamos el siguiente código:
1linklet vR = r / 255;2linklet vG = g / 255;3linklet vB = b / 255;Paso 2:
Convertir un RGB codificado (paso 1) con gamma a un valor lineal. RGB (estándar de computadora), por ejemplo, requiere una curva de potencia de aproximadamente V ^ 2.2, aunque la transformación "precisa" es:
1Donde V´ es el canal R, G o B codificado en gamma de RGB. Esto se realizó con las siguientes lineas del código:
1linkfunction sRGBtoLin(colorChannel) {2link if ( colorChannel <= 0.04045 ) {3link return colorChannel / 12.92;4link } else {5link return Math.pow((( colorChannel + 0.055)/1.055),2.4);6link }7link}Paso 3:
Para encontrar la luminancia aplicamos los coeficientes estándar para sRGB:
1Usando el código:
1linklet Y = ((rY * rLin) + (gY * gLin) + (bY * bLin));Adicionalmente recorremos todos los pixeles y aplicando la formula anteriormente mostrada.
1linkoImg.loadPixels();2link for (let i = 0; i < npixels; i += 4) {3link let y = luma(img.pixels[i], img.pixels[i+1],img.pixels[i+2])4link oImg.pixels[i] = y;5link oImg.pixels[i + 1] = y;6link oImg.pixels[i + 2] = y;7link oImg.pixels[i + 3] = img.pixels[i+3];8link }9linkoImg.updatePixels();
A continuación se muestran los resultados obtenidos aplicando las funciones anteriormente mencionadas. Arriba izquierda se muestra la imagen original, arriba derecha se muestra con la aplicación de la función predeterminada de funcion p5js, abajo izquierda se muestra aplicando luma, abajo derecha se muestra aplicando el promedio RGB
Adicionalmente se realizó el mismo procedimiento para video, se muestra a continuación:
Adicionalmente se realizó el mismo procedimiento para video, se muestra a continuación:
Promedio RGB en video:
Promedio luma en video:
Nota: Pulsar sobre el canvas para reanudar el video
Código para promedio RGB:
1linkfunction draw() {
2link image(fingers,0,0);
3link fingers.loadPixels();
4link loadPixels();
5link
6link for (let x = 1; x < fingers.width; x++) {
7link for (let y = 1; y < fingers.height; y++) {
8link let index = 4 * (x + fingers.width * y);
9link let average = (fingers.pixels[index] + fingers.pixels[index + 1] + fingers.pixels[index + 2]) / 3;
10link pixels[index] = average;
11link pixels[index + 1] = average;
12link pixels[index + 2] = average;
13link pixels[index + 3] = fingers.pixels[index + 3];
14link }
15link }
16link updatePixels();
17link}
Código para Luma:
1linkfunction draw() {
2link image(fingers,0,0);
3link fingers.loadPixels();
4link loadPixels();
5link for (let x = 1; x < fingers.width; x++) {
6link for (let y = 1; y < fingers.height; y++) {
7link let index = 4 * (x + fingers.width * y);
8link let lum = luma(fingers.pixels[index], fingers.pixels[index + 1],fingers.pixels[index + 2])
9link pixels[index] = lum;
10link pixels[index + 1] = lum;
11link pixels[index + 2] = lum;
12link pixels[index + 3] = fingers.pixels[index + 3];
13link }
14link }
15link updatePixels();
16link}
Explicación más detallada en: https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color