Skip to content

Sesion Laboratorio 12 Practica 5 1

Jesús Parrado Alameda edited this page Apr 25, 2023 · 15 revisions

Sesión Laboratorio 12: Práctica 5-1

  • Tiempo: 2h
  • Fecha: Jueves, 20 de Abril de 2023
  • Objetivos de la sesión:
    • Presentar la práctica 5
    • Aprender a acceder a los píxeles de las imágenes
    • Utilizar los filtros de imágenes para simular el tráfico en la red
    • Usar los deslizadores para simular los umbrales de carga en los nodos

Contenido

Introducción

En esta práctica vamos a utilizar los fundamentos para manipular imágenes en las aplicaciones WEB y a utilizarlos para simular el tráfico en la red.

Utilizaremos técnicas de filtros de imagen, que nos van a servir para simular como sería enviar paquetes a través de la red, y cómo afectaría al envío de los paquetes los cambios en la congestión de la red.

Vamos a aprovechar vuestros conocimientos sobre los filtros digitales de imágenes, y los vamos a poner en práctica.

Ya sabemos cómo hacer dibujos en el canvas.

Ahora practicaremos leyendo el canvas como una imagen y aplicando filtros para simular la red.

Si quieres ver en qué consisten estos filtros de imagen, puedes echar un vistazo a la práctica que realizó Ana Poveda García en el curso 2019-2020.

La puedes probar desde este enlace

Vamos a utilizar algunos de los conocimientos de la práctica de Ana, pero NO es la práctica que vamos a hacer este año.

Para saber qué vamos a hacer este año, por favor, sigue leyendo.

Enunciado de la Práctica 5 (ESPECIFICACIONES)

Diseñar una aplicación en javascript que simula el envío de paquetes a través de internet.

Vamos a implementar una simulación muy básica.

La idea es simular el envío de una imagen a través de internet de un emisor a un receptor.

Para eso tendrá que atravesar la red y por eso sufrirá un determinado retardo.

Asumiremos que el retardo es constante durante toda la transmisión.

Que el retardo va a depender de el número de nodos a atravesar que será un número comprendido entre 3 y 8.

Y el retardo en cada nodo que podrá ser un número comprendido entre 1ms y 5ms.

Con estos dos valores obtendremos un valor de retardo medio que nos servirá para actualizar nuestra simulación.

Manipulación de imágenes y seguridad

Para manipular imágenes desde nuestros programas javascript utilizaremos el Canvas.

Mediante la función getImageData() obtendremos los datos en crudo de la imagen y así podremos leer y modificar la imagen.

Este método, sin embargo, puede ser usado para provocar ataques XSS.

Por ello, este método está protegido y genera excepciones de seguridad cuando se usa con imágenes no autorizadas.

Este es el típico mensaje de ERROR que se obtiene en la consola del navegador:

A efectos prácticos, esto significa que No podemos ejecutar el código javascritpt que use getImageData() directamente desde el navegador (bien directamente desde el Atom, con el previsualizador, o abriendo directamente el html con el protocolo file://), como hemos hecho hasta ahora, sino que las imágenes a usar sólo pueden estar en el mismo servidor en el que se encuentra la web.

La solución para trabajar en local es lanzar nuestro propio servidor web desde la carpeta donde tenemos nuestros ficheros html y js de nuestra práctica.

Esto lo podemos hacer fácilmente usando el servidor que viene integrado con en uno de los módulos de python.

Así, hay que abrir un terminal y ejecutar:

python3 -m http.server

(o llamando python en vez de python3, según la versión que tengas instalada)

Esto es válido para cualquier sistema operativo (Linux, Max, Windows), pero es necesario tener python instalado.

Al ejecutar este comando se lanza el servidor.

Para ver en el navegador nuestra práctica hay que acceder a esta URL: http://0.0.0.0:8000/

Puerto ocupado por otro servidor

Si el puerto 8000 está en uso verás un error en la consola, prueba con el siguiente:

python3 -m http.server 8001

Y accede al servidor con la URL: http://0.0.0.0:8001/

Nota sobre Windows

Si lo estás probando en una máquina windows, usa este comando para lanzar el servidor:

python -m http.server --bind 127.0.0.1 8000

y la URL será esta: http://127.0.0.1:8000

Para parar el servidor

Utiliza el siguiente comando para parar el servidor en el terminal

CTRL + C

Ejemplo 1: Copiando una imagen al canvas

Manipularemos la imagen que esté situada sobre el canvas.

Por ello, el primer paso es colocar nuestra imagen origen en el canvas.

Esto lo hacemos invocando al método drawImage del contexto 2D del canvas.

Utilizaremos como imagen el logo de la URJC, pero puedes usar la que tú quieras: logoURJC.png

Es importante que te la descargues y la coloques en el mismo directorio que los ficheros html, css y js de tu práctica

Este es el código HTML usado en este ejemplo

  • Fichero HTML: Ej-01.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <script src="Ej-01.js" defer></script>
    <title>Ejemplo 1</title>
</head>
<body>
    <p>Imagen original</p>
    <img src="logoURJC.png" id="imagesrc">
    <p>Imagen manipulada</p>
    <canvas id="canvas"></canvas>
</body>
</html>

En la hoja de estilo simplemente se cambia el fondo a gris para que las imágenes, que tienen fondo blanco, resalten más.

  • Fichero CSS: style.css
body {
  background-color: grey;
}

El código javascript establece el tamaño del canvas para que sea igual al de la imagen original e inserta la imagen en él.

  • Fichero: Ej-01.js
console.log("Ejecutando JS....")

//-- Obtener elementos del DOM
const canvas = document.getElementById('canvas');
const img = document.getElementById('imagesrc')
const ctx = canvas.getContext('2d');

//-- Función de retrollamada de imagen cargada
//-- La imagen no se carga al instante, sino que
//-- lleva un tiempo. Sólo podemos acceder a ella una vez
//-- que esté totalmente cargada
img.onload = function () {

  console.log("Imagen cargada");

  //-- Se establece como tamaño del canvas el mismo
  //-- que el de la imagen original
  canvas.width = img.width;
  canvas.height = img.height;

  //-- Situar la imagen original en el canvas
  //-- No se han hecho manipulaciones todavia
  ctx.drawImage(img, 0,0);
};

console.log("Fin...");

Ahora, para probarlo, lanzamos primero el servidor para evitar los problemas de seguridad (No hace falta lanzarlo cada vez, se ejecuta una vez y permanecerá ahí hasta que salgamos pulsando Ctrl-C).

Desde el navegador nos conectamos esta URL: http://0.0.0.0:8000/

(También valdrían estas: http://localhost:8000, http://127.0.0.1).

Abrimos la consola del desarrollador para ver lo que está ocurriendo.

En la parte superiores está la imagen original.

Y en la parte inferior está la imagen copiada en el canvas.

Esta será la que manipularemos.

También nos fijaremos en el orden en el que aparecen las trazas en la consola.

Vemos que el mensaje "Fin" que se ha situado en el código en la parte final, NO es lo último que aparece.

Lo último es el mensaje que hemos situado en la función de retrollamada de la carga de la imagen.

Esto es debido a que la imagen tarda un tiempo en cargarse.

Sólo cuando se ha terminado de cargar, se ejecuta su función de retrollamada (callback), que es justo lo que queríamos.

¡Ya lo tenemos todo listo para empezar a manipularla!

Extra

Si te quieres librar del dichoso mensaje de favicon no encontrado puedes utilizar este: URJC favicon

Y colocarlo en tus proyectos.

Ya sabes, todo suma ;)

Ejemplo 2: Accediendo a los píxeles de la imagen

Las imágenes están formadas por unos puntitos muy pequeños, llamados píxeles.

Cada píxel está formado a su vez por tres componentes, una roja, una azul y una verde.

La mezcla de esos colores primarios genera el resto de colores.

Cada componente se indica mediante un byte, por lo que tiene valores entre 0 y 255.

Además se añade una cuarta componente, el grado de transparencia, también de un byte.

Por ello, cada píxel de la imagen se representa 4 bytes: 3 para las componentes roja, verde y azul y uno adicional para el grado de transparencia.

Para acceder a la información de los píxeles usamos el método getImageData() del contexto del canvas.

Se le pasan como parámetros la esquina superior izquierda y la inferior derecha de la región que queremos leer.

Para leer la imagen completa del canvas usaremos esta instrucción.

let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);

El objeto creado, imgData, es el que contiene el array data con la información de todos los píxeles.

Para acceder más fácilmente lo situamos en una variable nueva, que llamaremos también data:

let data = imgData.data

Las primeras cuatro posiciones del array (0,1,2 y 3) se corresponden con el pixel (0,0), situado en la esquina superior izquierda, las siguientes cuatro con el situado a su derecha, en (1,0) y así sucesivamente hasta llegar al último elemento, que es el pixel de la esquina inferior derecha.

En esta figura se muestran las posiciones del array correspondientes a la imagen de prueba, que tiene 400x179 píxeles.

Puesto que cada pixel tiene 4 bytes, en las posiciones *múltiplo de 4 se encuentran los canales rojos ( data[ix4] ), en las siguientes ( data[ix4 + 1] ) los verdes, luego los azules ( data[ix4 + 2] ) y finalmente la transparencia ( data[ix4 + 3] ).

En este código de ejemplo se accede al array data de la imagen y se muestran en la consola su tamaño.

Además, se muestran la altura y la anchura de la imagen, el total de píxeles y se calcula el tamaño que debería tener data para comprobar, que es correcto.

Así, el número total de píxeles se obtiene multiplicando la altura por la anchura.

Como cada pixel ocupa 4 bytes, en total el tamaño del array de datos debería ser de 4 por el número total de píxeles.

  • Fichero: Ej-02.js
console.log("Ejecutando JS....")

//-- Obtener elementos del DOM
const canvas = document.getElementById('canvas');
const img = document.getElementById('imagesrc')
const ctx = canvas.getContext('2d');

//-- Función de retrollamada de imagen cargada
//-- La imagen no se carga al instante, sino que
//-- lleva un tiempo. Sólo podemos acceder a ella una vez
//-- que esté totalmente cargada
img.onload = function () {

  //-- Se establece como tamaño del canvas el mismo
  //-- que el de la imagen original
  canvas.width = img.width;
  canvas.height = img.height;

  //-- Situar la imagen original en el canvas
  //-- No se han hecho manipulaciones todavia
  ctx.drawImage(img, 0,0);

  //-- Obtener la imagen del canvas en pixeles
  let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);

  //-- Obtener el array con todos los píxeles
  let data = imgData.data

  //-- Obtener el numero total de elementos en el array
  console.log("Tamaño de data: " + data.length)

  //-- El número total de pixeles es la altura por la anchura
  npixels = canvas.width * canvas.height
  console.log("Anchura (en pixeles): " + canvas.width)
  console.log("Altura (en pixeles): " + canvas.height)
  console.log("Pixeles totales: " + npixels)

  //-- Puesto que cada pixel ocupa 4 bytes, el array de píxeles
  //-- tiene un tamaño de 4 * numero de pixeles
  console.log("Total de datos de la imagen: " + npixels * 4)
};

console.log("Fin...");

Al ejecutarlo en el navegador obtenemos esta información en la consola:

Efectivamente, el tamaño del array data coincide con los cálculos hechos: 286400 posiciones

Ejemplo 3: Pintando un pixel rojo

Llega el momento de manipular la imagen: cambiaremos un pixel al color rojo.

Para ello tenemos que elegir un pixel de una posición, por ejemplo el (200, 50) y cambiar sus canales.

Pondremos el canal rojo a tope (255) y los canales verde y azul a 0.

El de la transparencia lo dejaremos como esté.

Primero calculamos la posición del pixel en el array.

Es el pixel de la posición (200, 50): Hay 50 líneas de una anchura igual a canvas.width.

En total 50*canvas.width píxeles.

A esto le sumamos los 200 pixeles de la posición horizontal:

let i = 200 + 50*canvas.width;

Y ahora cambiamos los valores del pixel que está a partir de la posición i del array:

data[i*4] = 255;   //-- Canal rojo
data[i*4 + 1] = 0; //-- Canal verde
data[i*4 + 2] = 0; //-- Canal azul

Por último actualizamos la imagen del canvas con los nuevos datos.

Esto lo hacemos ejecutando el método putImageData()

ctx.putImageData(imgData, 0, 0);

El código completo es el siguiente:

  • Fichero: Ej-03.js
console.log("Ejecutando JS....")

//-- Obtener elementos del DOM
const canvas = document.getElementById('canvas');
const img = document.getElementById('imagesrc')
const ctx = canvas.getContext('2d');

//-- Función de retrollamada de imagen cargada
//-- La imagen no se carga instantaneamente, sino que
//-- lleva un tiempo. Sólo podemos acceder a ella una vez
//-- que esté totalmente cargada
img.onload = function () {

  //-- Se establece como tamaño del canvas el mismo
  //-- que el de la imagen original
  canvas.width = img.width;
  canvas.height = img.height;

  //-- Situar la imagen original en el canvas
  //-- No se han hecho manipulaciones todavía
  ctx.drawImage(img, 0,0);

  //-- Obtener la imagen del canvas en pixeles
  let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);

  //-- Obtener el array con todos los píxeles
  let data = imgData.data

  //-- data[0] es el canal rojo del pixel de la posición 0,0
  //-- data[1] es el canal verde del pixel 0,0
  //-- data[2] es el canal azul del pixel 0,0
  //-- data[3] es el canal de transparencia del pixel 0,0
  //-- data[4] es el canal ROJO del pixel 1,0
  //-- ....
  //-- En general, para el pixel i
  //-- data[4*i] es el canal rojo
  //-- data[4*i + 1]: Canal verde
  //-- data[4*i + 2]: Canal azul
  //-- data[4*i + 3]: Canal de transparencia

  //-- Colocar un pixel rojo en (200,50)

  //-- Obtener el numero de pixel a partir de su posición
  let i = 200 + 50*canvas.width;

  //-- Pixel rojo: canal rojo a tope. Resto de colores a 0
  //-- La transparencia no se modifica
  data[i*4] = 255;    //-- Canal Rojo
  data[i*4 + 1] = 0;  //-- Canal Verde
  data[i*4 + 2] = 0;  //-- Canal azul

  //-- Poner la imagen modificada en el canvas
  ctx.putImageData(imgData, 0, 0);
};

console.log("Fin...");

Al ejecutarlo en el navegador veremos un pixel rojo en la zona blanca.

Es un pixel muy pequeño, hay que fijarse bien para verlo:

¡Nuestra primera manipulación de imagen!

Ejemplo 4: Eliminar el canal rojo de toda la imagen

Haremos nuestro primer filtro.

Uno que elimine toda la componente roja de la imagen original.

Para ello sólo hay que recorrer todos los píxeles del array poniendo a cero el rojo y dejando el resto igual.

Sabemos que esta componente está en las posiciones 0, 4, 8... i * 4 así que sólo hay que usar un bucle for que recorra estos valores y lo tendremos listo.

for (let i = 0; i < data.length; i+=4) {
    data[i] = 0; //-- Canal rojo a 0
  }

El código completo es este:

  • Fichero: Ej-04.js
console.log("Ejecutando JS....")

//-- Obtener elementos del DOM
const canvas = document.getElementById('canvas');
const img = document.getElementById('imagesrc')
const ctx = canvas.getContext('2d');

//-- Función de retrollamada de imagen cargada
//-- La imagen no se carga al instante, sino que
//-- lleva un tiempo. Sólo podemos acceder a ella una vez
//-- que esté totalmente cargada
img.onload = function () {

  //-- Se establece como tamaño del canvas el mismo
  //-- que el de la imagen original
  canvas.width = img.width;
  canvas.height = img.height;

  //-- Situar la imagen original en el canvas
  //-- No se han hecho manipulaciones todavía
  ctx.drawImage(img, 0,0);

  //-- Obtener la imagen del canvas en pixeles
  let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);

  //-- Obtener el array con todos los píxeles
  let data = imgData.data

  //-- Eliminar el canal Rojo:recorrer el array de datos
  //-- eliminado el canal rojo y dejando el resto igual que
  //-- estaba
  for (let i = 0; i < data.length; i+=4) {
    data[i] = 0; //-- Canal rojo a 0
  }

  //-- Poner la imagen modificada en el canvas
  ctx.putImageData(imgData, 0, 0);

  console.log("hola....");
};

console.log("Fin...");

Al ejecutarlo en el navegador obtenemos esto:

Observamos que la corona encima de la U se ha transformado en negro.

El fondo, que era blanco, ahora es azul claro: sólo tiene componentes verde y azul.

Lo que era negro lo sigue siendo (el negro no tiene componente roja).

Ejemplo 5: Umbral de color rojo

Haremos un filtro usando el deslizador para variar el umbral de color rojo.

Los deslizadores los vimos en la Sesión 7 de Teoría

Todos aquellos píxeles cuyo nivel de rojo esté por encima del umbral, se limitarán al valor de este umbral.

O dicho de otra manera, el umbral determina el nivel máximo de rojo permitido.

Este es el nuevo fichero HTML.

Estamos utilizando esta imagen y debajo de ella se sitúa el deslizador.

La imagen original está oculta.

Sólo se muestra la final.

  • Fichero: Ej-05.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="Ej-05.css">
    <script src="Ej-05.js" defer></script>
    <title>Ejemplo 5</title>
</head>
<body>
    <canvas id="canvas"></canvas>
    <img src="FPGA.jpg" id="imagesrc">
    <p>Establece el umbral de rojo:</p>
    <input type="range" id="deslizador" min="0" max="255" value="255"/>
    <p id="range_value">00</p>
</body>
</html>

En el fichero de estilo indicamos que la imagen identificada como imagesrc no esté visible:

  • Fichero: Ej-05.css
#imagesrc {
  display:none;
}

El filtrado se realiza con este bucle:

  //-- Filtrar la imagen según el nuevo umbral
    for (let i = 0; i < data.length; i+=4) {
      if (data[i] > umbral)
        data[i] = umbral;
    }

El código completo en javascript es el siguiente:

  • Fichero: Ej-05.js
console.log("Ejecutando JS....")

//-- Obtener elementos del DOM
const canvas = document.getElementById('canvas');
const img = document.getElementById('imagesrc');
const ctx = canvas.getContext('2d');

//-- Acceso al deslizador
const deslizador = document.getElementById('deslizador');

//-- Valor del deslizador
const range_value = document.getElementById('range_value');

//-- Función de retrollamada de imagen cargada
//-- La imagen no se carga instantaneamente, sino que
//-- lleva un tiempo. Sólo podemos acceder a ella una vez
//-- que esté totalmente cargada
img.onload = function () {

  //-- Se establece como tamaño del canvas el mismo
  //-- que el de la imagen original
  canvas.width = img.width;
  canvas.height = img.height;

  //-- Situar la imagen original en el canvas
  //-- No se han hecho manipulaciones todavía
  ctx.drawImage(img, 0,0);

  console.log("Imagen lista...");
};


//-- Función de retrollamada del deslizador
deslizador.oninput = () => {
  //-- Mostrar el nuevo valor del deslizador
  range_value.innerHTML = deslizador.value;

  //-- Situar la imagen original en el canvas
  //-- No se han hecho manipulaciones todavía
  ctx.drawImage(img, 0,0);

  //-- Obtener la imagen del canvas en pixeles
  let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);

  //-- Obtener el array con todos los píxeles
  let data = imgData.data

  //-- Obtener el umbral de rojo del deslizador
  umbral = deslizador.value

  //-- Filtrar la imagen según el nuevo umbral
  for (let i = 0; i < data.length; i+=4) {
    if (data[i] > umbral)
      data[i] = umbral;
  }

  //-- Poner la imagen modificada en el canvas
  ctx.putImageData(imgData, 0, 0);
}

console.log("Fin...");

En esta animación lo vemos en acción:

Filtro de grises

Un filtro para eliminar los colores y quedarse sólo con el nivel de grises se hace de una forma parecida.

Hay que obtener los niveles de color y calcular el brillo usando esta ecuación:

brillo = (3 * r + 4 * g + b)/8

Luego hay que asignar este valor a los tres canales (para que todos tengan el mismo)

Prototipo Simulador de red

En el documento html situamos los elementos que vamos a utilizar, varias imágenes, algunas ocultas otras no.

El canvas para la simulación, y el deslizador para los controles.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="sim-net.css">
    <script src="sim-net.js" defer></script>
    <title>Simulando la Red</title>
</head>
<body>
    <p>Imagen en Origen</p>
    <img src="logoURJC.png" id="imagesrc">
    <img src="logoURJCh.png" id="imagesrchide">    
    <img src="cloud.jpg" id="cloud">
    <button id="bsend">Enviar</button>    
    <p>Imagen en Destino</p>
    <canvas id="canvas"></canvas>
    <input type="range" id="netdelay" min="1" max="1000" value="1"/>
    <p id="netdelay_value">0</p>    
    <p>La red</p>
    <img src="net.svg">    
</body>
</html>

Con el css le damos color al fondo, y ocultamos las imágenes que no utilizamos de partida.

body {
    background-color: grey;
  }

#cloud {
  display: none;
}

#imagesrchide {
  display: none;
}

En javascript es donde tenemos la lógica de la aplicación, al pulsar el botón de enviar simulamos la transmisión de paquetes.

Yo he simulado el envío de la imagen línea a línea horizontal, pero hay más posibilidades.

console.log("Montando la red...")

const gui = {
  bsend : document.getElementById("bsend"),
  netdelay : document.getElementById("netdelay"),
  netdelayvalue : document.getElementById("netdelay_value"),
}

//-- Obtener elementos del DOM
const canvas = document.getElementById('canvas');
const imgBack = document.getElementById('imagesrchide');
const imgCloud = document.getElementById('cloud');
const imgFront = document.getElementById('imagesrc');
const ctx = canvas.getContext('2d');

//-- Gestionar el estado el envío
const state = {
  sendingImage: false,
  totalTime: 0,
  totalPackages:0,
  sendingPackage:0,
  netDelay: 1,
  netDelayDefault: 1,
  loop: null
}

//-- Iniciar el valor del deslizador con el valor de la 
// variable de estado para el delay
gui.netdelayvalue.innerHTML = state.netDelay;

//-- Cuando está disponible cargo la imagen con la nube para represntar el destino
imgCloud.onload = function () {

  //-- Se establece como tamaño del canvas el mismo
  //-- que el de la imagen original
  canvas.width = imgCloud.width;
  canvas.height = imgCloud.height;

  //-- Situar la imagen original en el canvas
  //-- No se han hecho manipulaciones todavía
  ctx.drawImage(imgCloud, 0, 0);

}

//-- función de callback para el envío de la imagen
gui.bsend.onclick = () => {
  sendImage()
}

//-- función de callback para actualizar los valores del 
// deslizador y la variable de estado para el delay
gui.netdelay.oninput = () => {
  gui.netdelayvalue.innerHTML = gui.netdelay.value;
  state.netDelay = gui.netdelay.value;
}

//-- simulación del envío de la imagen
//-- la he planteado como que cada línea horizontal de la imagen
//-- es un paquete de datos, que sufrirá el retardo correspondiente.
//-- https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData
const sendImage = () => {

  console.log("Comienzo a enviar...");

  //-- Se establece como tamaño del canvas el mismo
  //-- que el de la imagen original
  canvas.width = imgFront.width;
  canvas.height = imgFront.height;  
 
  //-- Situar la imagen original en el canvas
  //-- No se han hecho manipulaciones todavía
  ctx.drawImage(imgFront, 0, 0);

  //-- Obtener la imagen del canvas en pixeles
  //let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);

  state.totalPackages = canvas.height;
  state.sendingImage = true;

  //-- declaro las variables fuera del loop
  //-- esta me servirá para seleccionar el rectángulo de la imagen
  let imgData = ctx.getImageData(0, 0, 1, 1)
  
  //-- Obtener el array con todos los píxeles
  let data = imgData.data

  state.loop = setInterval(() => {

    state.totalTime++
    state.sendingPackage++

    //-- dimensiones del rectángulo 1
    sx1 = 0;
    sy1 = 0;
    sw1 = canvas.width;
    sh1 = state.sendingPackage;

    imgData = ctx.getImageData(sx1, sy1, sw1, sh1);

    //-- Obtener el array con todos los píxeles
    data = imgData.data

    //-- cambiamos el canal a rojo del rectángulo que hemos seleccionado
    for (let i = 0; i < data.length; i+=4) {
      data[i] = 0; //-- Canal rojo a 0
    }
    
    //-- dimensiones del rectángulo 2
    sx2 = sx1;
    sy2 = sh1+1;
    sw2 = sw1;
    sh2 = state.totalPackages - sh1;

    // if (sh2 > 0) {
    //   //-- seleccionamos el rectángulo 2
    //   imgData = ctx.getImageData(sx2, sy2, sw2, sh2);

    //   //-- Obtener el array con todos los píxeles
    //   data = imgData.data
  
    //   for (let i = 0; i < data.length; i+=4) {
    //     // brillo = (3 * r + 4 * g + b)/8
    //     //let brillo = (3 * data[i] + 4 * data[i+1] + data[i+2])/8
    //     //data[i] = brillo;
    //     //data[i+1] = brillo;
    //     //data[i+2] = brillo; 
    //     //data[i] = 0;
    //     //data[i+1] = 0;
    //     data[i+2] = 0;         
    //   }  
    // }

    //-- Poner la imagen modificada en el canvas
    ctx.putImageData(imgData, 0, 0);

    // Paramos el loop si hemos terminado de enviar
    if (state.sendingPackage == state.totalPackages) {
      ctx.drawImage(imgBack, 0, 0); 
      console.log("Envio terminado...");
      state.sendingImage = false;             
      clearInterval(state.loop);
    }

    console.log("Enviando...");
  }, state.netDelay )
}

console.log("Red preparada...");

Para modelar la congestión de la red, puedes utilizar una función para obtener el delay de cada nodo en función del número de nodos y el retardo en cada nodo.

¡A practicar!

Si no lo has hecho ya, practica con los ejercicios propuestos en esta sesión.

Con esto ya tendrás una versión mínima de la aplicación de filtrado que utilizaremos para simular la red.

Da los últimos retoques añadiendo estilo y dejando la interfaz un poco más bonita.

Resumen de tareas propuestas

  • Implementa los ejemplos 1 - 5 de esta sesión y guárdalos en la carpeta P5

Conclusiones

Al terminar esta práctica ya sabrás cómo procesar imágenes con Javascript.

Y ya podrás poner en práctica los conocimientos adquiridos en otras asignaturas sobre filtrado de imágenes.

Ahora ya los puedes utilizar también para simular tu red.

Autor

Jesús Parrado Alameda (jesusgpa)

Creditos

Licencia

Enlaces

Página principal


Teoría

Práctica 0: Herramientas

Práctica 1: CV

Práctica 2: Boom

Práctica 3: Tiro parabólico

Práctica 4: The Memory Games

Práctica 5: Simulando la red

Examenes

Curso 2022/2023

  • [2023 - 16 de Marzo: L3210 9:00 - 12:00 Parcial 1 ]
  • [2023 - 22 de Mayo L3208 9:00 - 12:00 : Parcial 2 ]
  • [2023 - 14 de Junio L3208 18:00 - 21:00 : Final. Conv. extraordinaria ]
Clone this wiki locally