To be able to edit code and run cells, you need to run the notebook yourself. Where would you like to run the notebook?

This notebook takes about 30 seconds to run.

In the cloud (experimental)

Binder is a free, open source service that runs scientific notebooks in the cloud! It will take a while, usually 2-7 minutes to get a session.

On your computer

(Recommended if you want to store your changes.)

  1. Download the notebook:
  2. Run Pluto

    (Also see: How to install Julia and Pluto)

  3. Open the notebook file

    Type the saved filename in the open box.

Frontmatter

If you are publishing this notebook on the web, you can set the parameters below to provide HTML metadata. This is useful for search engines and social media.

Author 1

Cálculo científico con Julia 🧪

¿Qué es Julia?

Julia es un moderno lenguaje de programación especialmente diseñado para el cálculo científico que destaca principalmente en la construcción de modelos matemáticos.

👀 Reading hidden code
md"""
# Cálculo científico con Julia 🧪

!!! question "¿Qué es Julia?"
Julia es un moderno lenguaje de programación especialmente diseñado para el cálculo científico que destaca principalmente en la construcción de modelos matemáticos.
"""
9.5 ms

Filtros para imágenes

En este taller veremos como las imágenes pueden representarse matemáticamente como matrices y cómo podemos diseñar filtros para cambiar el aspecto de las imágenes con Julia.

👀 Reading hidden code
md"""
# Filtros para imágenes

En este taller veremos como las imágenes pueden representarse matemáticamente como **matrices** y cómo podemos diseñar filtros para cambiar el aspecto de las imágenes con Julia.
"""
372 μs

Representación de imágenes como matrices

Si miras con lupa una imagen digital, verás está formada por pequeños puntitos de colores llamados píxeles que se organizan en forma de tabla o matriz conocida como mapa de bits. El número de filas y columnas de esa matriz es la resolución de la imagen.

El color de cada pixel se obtiene mediante la combinación de los colores básicos R (red), G (green) y B (blue) y esa combianción se puede expresar como un código numérico.

👀 Reading hidden code
244 μs

Mapa de bits

👀 Reading hidden code
55.8 ms

En este taller trabajaremos con imágenes en blanco y negro que son más sencillas de representar matricialmente.

Mapa de bits en escala de grises.

👀 Reading hidden code
261 μs

Podemos definir fácilmente una variable en Julia para representar un pixel con un nivel de gris determiando por un parámetro interactivo.

Observa cómo cambia de color el píxel de más abajo cuando movelos el deslizador del nivel del gris.

👀 Reading hidden code
288 μs
0.0
👀 Reading hidden code
278 ms
👀 Reading hidden code
8.2 ms

Ahora podemos definir una matriz de 3 x 3 (3 filas y 3 columnas) con números entre 0 y 1 que representan el nivel de gris.

En Julia las matrices se representan entre corchetes [ ], separando sus filas con punto y coma ; y las columnas con espacios.

👀 Reading hidden code
425 μs
3×3 Matrix{Float64}:
 0.1  0.2  0.3
 0.4  0.5  0.6
 0.7  0.8  0.9
matriz = [0.1 0.2 0.3; 0.4 0.5 0.6; 0.7 0.8 0.9]
👀 Reading hidden code
17.9 ms

A partir de esta matriz podemos usar el paquete Images de Julia para generar fácilmente una imagen de 3x3 con pixels cuyos niveles de gris se corresponden con los valores de la matriz anterior.

👀 Reading hidden code
287 μs
img = Gray.(matriz)
👀 Reading hidden code
92.6 ms

Ahora que ya entiendes cómo se representa una imagen matemáticamente mediante una matriz, vamos a cargar una imagen real con la que trabajaremos. Selecciona la imagen que más prefieras.

👀 Reading hidden code
288 μs
👀 Reading hidden code
3.4 s
👀 Reading hidden code
1.7 ms

A continuación se muestra la matriz que representa esta imagen.

👀 Reading hidden code
223 μs
512×512 reinterpret(reshape, N0f8, ::Array{Gray{N0f8},2}) with eltype N0f8:
 0.569  0.22   0.192  0.349  0.537  0.353  …  0.271  0.518  0.443  0.6    0.694
 0.455  0.396  0.157  0.263  0.353  0.212     0.498  0.475  0.51   0.584  0.49
 0.302  0.447  0.18   0.18   0.384  0.235     0.482  0.384  0.392  0.345  0.318
 0.278  0.533  0.373  0.188  0.325  0.471     0.333  0.435  0.286  0.294  0.275
 0.341  0.478  0.518  0.196  0.298  0.341     0.365  0.259  0.231  0.314  0.337
 0.322  0.298  0.624  0.239  0.282  0.376  …  0.267  0.208  0.333  0.596  0.714
 0.169  0.2    0.525  0.51   0.275  0.478     0.239  0.357  0.725  0.776  0.643
 ⋮                                  ⋮      ⋱                       ⋮      
 0.412  0.435  0.518  0.569  0.58   0.506     0.4    0.365  0.322  0.325  0.325
 0.376  0.447  0.541  0.596  0.584  0.506     0.416  0.38   0.361  0.361  0.333
 0.435  0.525  0.596  0.541  0.549  0.498     0.4    0.341  0.388  0.353  0.349
 0.553  0.569  0.553  0.573  0.494  0.482     0.345  0.361  0.325  0.349  0.306
 0.612  0.553  0.514  0.467  0.404  0.467  …  0.333  0.322  0.31   0.314  0.271
 0.043  0.043  0.051  0.055  0.059  0.059     0.02   0.016  0.027  0.016  0.016
👀 Reading hidden code
41 ns

Filtros de imágenes

Ahora veremos como podemos aplicar un filtro a la imagen seleccionada para provocar un cambio en su aspecto.

¿Qué es un filtro?

Un filtro es una transformación que se aplica a cada uno de los pixels de la imagen.

Una transformación habitual es una convolución que consiste en multiplicar cada pixel y sus pixels vecinos por una pequeña matriz. El nuevo valor del pixel se obtienen sumando los valores de estos productos.

Dependiendo de los valores de la matriz de convolución, podemos obtener filtros que provocarán distintos cambios de aspecto de la imagen.

La siguiente función de Julia aplica la transformación de convolución. Esta función recorre los pixels de la matriz original y aplica la transformación de convolución a cada uno de ellos, pero no te preocupes si no la entiendes del todo.

👀 Reading hidden code
510 μs
convolucion (generic function with 1 method)
function convolucion(imagen, filtro)

# Otenemos las dimensiones de la matriz de la imagen original
imagen_filas, imagen_columnas = size(imagen)
filtro_filas, filtro_columnas = size(filtro)

# Inicializamos la matriz de la imagen resultante con ceros
filtrada = zeros(imagen_filas-filtro_filas+1, imagen_columnas-filtro_columnas+1)
filtrada_filas, filtrada_columnas = size(filtrada)

# Aplicamos el filtro a cada pixel de la matriz original iterando sobre cada pixel por filas y columnas.
for i in 1:filtrada_filas
for j in 1:filtrada_columnas
filtrada[i,j] = sum(imagen[i:i+filtro_filas-1, j:j+filtro_columnas-1] .* filtro)
end
end
return filtrada
end
👀 Reading hidden code
2.2 ms

Filtro para difuminar

Vamos a empezar con un filtro sencillo para difuminar la imagen uniformemente. Para ello utilizaremos una matriz de convolución de 3x3 con los mismos valores. La intensidad del difuminado dependerá del valor de la matriz de convolución.

Como todos los valores de la matriz de convolución son iguales, el nuevo valor del pixel es la media de los valores del pixel y de sus vecinos.

A continuación definimos la matriz de un filtro de difuminado cuyos valores dependen del pámetro interactivo intensidad.

👀 Reading hidden code
445 μs
👀 Reading hidden code
107 ms
Loading more cells...