El procesamiento de imágenes digitales significa procesar la imagen digitalmente con la ayuda de una computadora. Usando el procesamiento de imágenes podemos realizar operaciones como mejorar la imagen, desenfocar la imagen, extraer texto de las imágenes y muchas más operaciones. Hay varias formas de procesar imágenes digitalmente. Aquí discutiremos el módulo Pillow de Python. Python Pillow se basa en la parte superior de PIL (Biblioteca de imágenes de Python) y se considera la bifurcación del mismo, ya que PIL se suspendió a partir de 2011. Pillow admite muchos formatos de archivo de imagen, incluidos BMP, PNG, JPEG y TIFF. La biblioteca fomenta la adición de soporte para formatos más nuevos en la biblioteca mediante la creación de nuevos decodificadores de archivos.
Este artículo tiene como objetivo proporcionar información sobre Python Pillow desde lo básico para avanzar con la ayuda de conceptos y ejemplos bien explicados. Entonces, no perdamos nada de tiempo y sumérjase profundamente en la Pillow.
Instalación
Python Pillow no viene integrado con Python. Para instalarlo, escriba el siguiente comando en la terminal.
pip install pillow
Después de la instalación, comencemos a usar el módulo de Pillow.
Apertura y visualización de la imagen
El módulo Pillow proporciona la función open() y show() para leer y mostrar la imagen respectivamente. Para mostrar la imagen, Pillow primero convierte la imagen a un formato .png (en el sistema operativo Windows) y la almacena en un búfer temporal y luego la muestra. Por lo tanto, debido a la conversión del formato de imagen a .png, es posible que se pierdan algunas propiedades del formato de archivo de imagen original (como la animación). Por lo tanto, se recomienda utilizar este método solo con fines de prueba.
Ejemplo:
Imagen utilizada para todos los siguientes ejemplos:
Python3
from PIL import Image # Location of the image img = Image.open("geek.jpg") img.show()
Producción:
Consulte los siguientes artículos para obtener información detallada sobre cómo abrir y mostrar imágenes.
Obtener información sobre la imagen abierta
Obtener el tamaño y el formato de la imagen
- El atributo de tamaño proporciona el tamaño de la imagen. Devuelve una tupla que contiene ancho y alto.
- El atributo de formato devuelve el formato del archivo de imagen.
Ejemplo:
Python3
from PIL import Image # Location of the image img = Image.open("geek.jpg") # size of the image print(img.size) # format of the image print(img.format)
Producción:
(287, 70) JPEG
Consulte el siguiente artículo para obtener información detallada sobre cómo obtener el tamaño y el formato de la imagen
- Encontrar la resolución de tamaño de la imagen en Python
- ¿Cómo encontrar el ancho y el alto de una imagen usando Python?
Obtener el modo de color de la imagen
El atributo de modo de la imagen indica el tipo y la profundidad del píxel en la imagen. Un píxel de 1 bit tiene un rango de 0-1 y un píxel de 8 bits tiene un rango de 0-255. Hay diferentes modos proporcionados por este módulo. Algunos de ellos son:
Modo | Descripción |
---|---|
1 | píxeles de 1 bit, en blanco y negro |
L | píxeles de 8 bits, escala de grises |
PAGS | Píxeles de 8 bits, asignados a cualquier otro modo mediante una paleta de colores |
RGB | Píxeles de 3 × 8 bits, color verdadero |
RGBA | Píxeles de 4 × 8 bits, color verdadero con máscara de transparencia |
Ejemplo:
Python3
from PIL import Image # Location of the image img = Image.open("geek.jpg") # mode of the image print(img.mode)
Producción:
RGB
Rotación de la imagen
El método de rotate() de la clase de imagen se usa para rotar la imagen en un ángulo particular en sentido contrario a las agujas del reloj alrededor de su centro. Después de rotar la imagen, las secciones de la imagen que no tienen valores de píxeles se rellenan con negro (para imágenes no alfa) y con píxeles completamente transparentes (para imágenes que admiten transparencia).
Sintaxis:
new_object = PIL.Image.Image.rotate(image_object, angle, resample=0, expand=0)
O
nuevo_objeto = imagen_objeto.rotar(ángulo, remuestreo=0, expandir=0)
Ejemplo:
Python3
# Importing Image module from # PIL package from PIL import Image import PIL # creating a image object (main image) im1 = Image.open(r"geek.jpg") # rotating a image 90 deg counter clockwise im1 = im1.rotate(90, PIL.Image.NEAREST, expand = 1) # to show specified image im1.show()
Producción:
Consulte los artículos a continuación para obtener información detallada sobre la rotación de la imagen.
Voltear la imagen
Image.transpose() se usa para transponer la imagen (voltear o rotar en pasos de 90 grados).
Sintaxis:
transponer (grado)
Las palabras clave FLIP_TOP_BOTTOM y FLIP_LEFT_RIGHT se pasarán al método de transposición para voltearlo.
- FLIP_TOP_BOTTOM: devuelve una imagen original volteada verticalmente
- FLIP_LEFT_RIGHT: devuelve una imagen original volteada horizontalmente
Ejemplo:
Python3
# importing PIL Module from PIL import Image # open the original image original_img = Image.open("geek.jpg") # Flip the original image vertically vertical_img = original_img.transpose(method=Image.FLIP_TOP_BOTTOM) vertical_img.save("vertical.png") vertical_img.show() # close all our files object original_img.close() vertical_img.close()
Producción:
Consulte los artículos a continuación para obtener información detallada sobre cómo voltear imágenes.
- Python PIL | Método Image.transpose()
- ¿Cómo voltear una imagen horizontal o verticalmente en Python?
Cambiar el tamaño de la imagen
Image.resize() devuelve una copia redimensionada de la imagen. La interpolación ocurre durante el proceso de cambio de tamaño, debido a que la calidad de la imagen cambia ya sea que se aumente la escala (se redimensione a una dimensión mayor que la original) o se reduzca la escala (se redimensione a una imagen más baja que la original). Por lo tanto, resize() debe usarse con precaución y al mismo tiempo proporcionar un valor adecuado para el argumento de remuestreo.
Sintaxis:
Image.resize(tamaño, remuestreo=0)
Ejemplo:
Python3
# Importing Image class from PIL module from PIL import Image # Opens a image in RGB mode im = Image.open(r"geek.jpg") # Size of the image in pixels # (size of original image) # (This is not mandatory) width, height = im.size # Setting the points for cropped image left = 4 top = height / 5 right = 154 bottom = 3 * height / 5 # Cropped image of above dimension # (It will not change original image) im1 = im.crop((left, top, right, bottom)) newsize = (300, 300) im1 = im1.resize(newsize) # Shows the image in image viewer im1.show()
Producción:
Consulte el siguiente artículo para obtener información detallada sobre cómo cambiar el tamaño de las imágenes.
- Python PIL | Método Image.resize()
- Cambiar la relación entre el ancho y el alto de una imagen usando Python – Pillow
Guardar la imagen
Image.save() guarda la imagen con el nombre de archivo dado. Si no se especifica ningún formato, el formato a utilizar se determina a partir de la extensión del nombre de archivo, si es posible. Puede utilizar un objeto de archivo en lugar de un nombre de archivo. En este caso, siempre debe especificar el formato. El objeto de archivo debe implementar los métodos de búsqueda, notificación y escritura, y debe abrirse en modo binario.
Sintaxis:
Image.save(fp, formato=Ninguno, **parámetros)
Ejemplo:
Python3
from PIL import Image size = (40, 40) img = Image.open(r"geek.jpg") print("Original size of the image") print(img.size) # resizing the image r_img = img.resize(size, resample = Image.BILINEAR) # resized_test.png => Destination_path r_img.save("resized_test.jpg") # Opening the new image img = Image.open(r"resized_test.jpg") print("\nNew size of the image") print(img.size)
Producción:
Original size of the image (287, 70) New size of the image (40, 40)
Hasta ahora, hemos aprendido los conceptos básicos de la Pillow. Ahora comencemos con algunas operaciones complejas, como desenfocar la imagen, fusionar dos imágenes o incluso crear una miniatura. Entonces, comencemos fusionando imágenes.
Combinar imágenes
Image.merge() se utiliza para fusionar un conjunto de imágenes de una sola banda en una nueva imagen multibanda.
Sintaxis:
PIL.Image.merge(modo, bandas)
Parámetros:
modo: el modo que se utilizará para la imagen de salida. Ver: Modos.
bandas: una secuencia que contiene una imagen de una sola banda para cada banda en la imagen de salida. Todas las bandas deben tener el mismo tamaño.
Devuelve: un objeto de imagen.
Nota: Usaremos el método Image.split() para dividir la imagen en bandas individuales.
Ejemplo:
Python3
# importing Image class from PIL package from PIL import Image # creating a object image = Image.open(r"geek.jpg") image.load() # Splitting the image into individual # bands r, g, b, = image.split() # merge function used im1 = Image.merge('RGB', (g, b, r)) im1.show()
Producción:
Combinar dos o más imágenes
Usando el método merge() también podemos fusionar dos o más imágenes. Tenemos que seleccionar dos imágenes del mismo tamaño o podemos cambiar el tamaño de la imagen. Luego, usando la función new() , crearemos una nueva imagen y pegaremos todas las imágenes allí. Vea el siguiente ejemplo para una mejor comprensión.
Ejemplo:
Imágenes utilizadas:
Python3
from PIL import Image img_01 = Image.open("digit-number-img-0.jpg") img_02 = Image.open("digit-number-img-1.jpg") img_03 = Image.open("digit-number-img-2.jpg") img_04 = Image.open("digit-number-img-3.jpg") img_01_size = img_01.size img_02_size = img_02.size img_03_size = img_02.size img_02_size = img_02.size print('img 1 size: ', img_01_size) print('img 2 size: ', img_02_size) print('img 3 size: ', img_03_size) print('img 4 size: ', img_03_size) new_im = Image.new('RGB', (2*img_01_size[0],2*img_01_size[1]), (250,250,250)) new_im.paste(img_01, (0,0)) new_im.paste(img_02, (img_01_size[0],0)) new_im.paste(img_03, (0,img_01_size[1])) new_im.paste(img_04, (img_01_size[0],img_01_size[1])) new_im.save("merged_images.png", "PNG") new_im.show()
Producción:
Consulte los siguientes artículos para obtener información detallada sobre la fusión de imágenes.
- Python PIL | Método Image.merge()
- ¿Cómo fusionar imágenes con el mismo tamaño usando la Pillow del módulo Python 3?
- Python | Copie y pegue imágenes en otra imagen usando la Pillow
- ¿Cómo fusionar una imagen PNG transparente con otra imagen usando PIL?
Creación de una miniatura
Image.thumbnail() convierte la imagen en una miniatura. Este método modifica la imagen para que contenga una versión en miniatura de sí misma, no más grande que el tamaño dado. Este método calcula un tamaño de miniatura apropiado para preservar el aspecto de la imagen, llama al método draft() para configurar el lector de archivos (donde corresponda) y finalmente cambia el tamaño de la imagen.
Nota: Esta función modifica el objeto Imagen en su lugar. Si también necesita usar la imagen de resolución completa, aplique este método a una copia() de la imagen original.
Ejemplo:
Imagen utilizada:
Python3
# importing Image class from PIL package from PIL import Image # creating a object image = Image.open(r"image.jpg") MAX_SIZE = (100, 100) # Creating the thumbnail image.thumbnail(MAX_SIZE) image.show()
Producción:
Consulte los siguientes artículos para obtener información detallada sobre la creación de miniaturas.
- Python PIL | Método Image.thumbnail()
- Genere una imagen en miniatura cuadrada o circular con Python – Pillow
Recortar la imagen
Recortar es el proceso de seleccionar solo una parte de la imagen. El método crop() se utiliza para recortar una parte rectangular de cualquier imagen.
Sintaxis:
PIL.Imagen.crop(caja = Ninguno)
Parámetros:
cuadro: una tupla de 4 que define la coordenada de píxel izquierdo, superior, derecho e inferior.
Ejemplo:
Python3
# Importing Image class from PIL module from PIL import Image # Opens a image in RGB mode im = Image.open(r"geek.jpg") # Size of the image in pixels # (size of original image) # (This is not mandatory) width, height = im.size # Setting the points for cropped image left = 5 top = height / 4 right = 164 bottom = 3 * height / 4 # Cropped image of above dimension # (It will not change original image) im1 = im.crop((left, top, right, bottom)) # Shows the image in image viewer im1.show()
Producción:
Consulte los siguientes artículos para obtener información detallada sobre cómo recortar imágenes.
Borrando la imagen
Si se observa cuidadosamente una imagen borrosa, lo más común es notar que la imagen es uniforme, lo que significa que no se observan los bordes. Un filtro utilizado para desenfoque también se denomina filtro de paso bajo porque permite que la baja frecuencia ingrese y detenga la alta frecuencia. La clase ImageFilter en la biblioteca de Pillows proporciona varios filtros que se pueden aplicar mediante el método filter() . Veamos algunos de los filtros de desenfoque proporcionados por la Pillow.
Desenfoque sencillo
Este método desenfoca la imagen utilizando la array kernel o mediante la array de convolución . Se puede aplicar usando el parámetro BLUR .
Sintaxis:
filtro(FiltroImagen.BLUR)
Nota: Para obtener más información, consulte ¿Qué es el desenfoque de imagen?
Ejemplo:
Python3
# Importing Image class from PIL module from PIL import Image # Opens a image in RGB mode im = Image.open(r"geek.jpg") # Blurring the image im1 = im.filter(ImageFilter.BLUR) # Shows the image in image viewer im1.show()
Producción:
Desenfoque gaussiano
El filtro gaussiano se implementa como un núcleo simétrico de tamaño impar (versión DIP de una array) que se pasa a través de cada píxel de la región de interés para obtener el efecto deseado. El kernel no es difícil de cambiar drásticamente de color (bordes) debido a que los píxeles hacia el centro del kernel tienen más peso hacia el valor final que la periferia. Un filtro Gaussiano podría considerarse como una aproximación de la Función Gaussiana (matemáticas). El módulo Pillow proporciona el kernel de desenfoque gaussiano predefinido que hace los cálculos subyacentes por nosotros.
Sintaxis:
ImageFilter.GaussianBlur(radio=2)
Ejemplo:
Python3
# Importing Image class from PIL module from PIL import Image # Opens a image in RGB mode im = Image.open(r"geek.jpg") # Blurring the image im1 = im.filter(ImageFilter.GaussianBlur(4)) # Shows the image in image viewer im1.show()
Producción:
Caja de desenfoque
El desenfoque de cuadro también se conoce como filtro lineal de cuadro. Los desenfoques de cuadro se utilizan con frecuencia para aproximar el desenfoque gaussiano. Un desenfoque de cuadro generalmente se implementa como un efecto de imagen que afecta a toda la pantalla. El color borroso del píxel actual es el promedio del color del píxel actual y sus 8 píxeles vecinos. Pillow proporciona el método BoxBlur() para hacer lo mismo.
Sintaxis:
ImageFilter.BoxBlur(radio)
Ejemplo:
Python3
# Importing Image class from PIL module from PIL import Image # Opens a image in RGB mode im = Image.open(r"geek.jpg") # Blurring the image im1 = im.filter(ImageFilter.BoxBlur(4)) # Shows the image in image viewer im1.show()
Producción:
Consulte los siguientes artículos para obtener información detallada sobre imágenes borrosas.
- Python PIL | Método GaussianBlur()
- Aplicar un filtro de Gauss a una imagen con Python
- Python PIL | Método BoxBlur()
Dibujar en imágenes
Pillow proporciona el módulo ImageDraw que proporciona gráficos 2D simples para objetos de imagen. Puede usar este módulo para crear nuevas imágenes, anotar o retocar imágenes existentes y generar gráficos sobre la marcha para uso web. Veamos diversas figuras o textos que podemos dibujar sobre la imagen.
Agregar texto
Agregar texto a una imagen a veces puede ser muy necesario, ya que se puede usar para proporcionar información útil a la imagen o también se puede usar para agregar una firma digital a la imagen. Con la Pillow, podemos agregar fácilmente un texto a cualquier imagen. Veamos el siguiente ejemplo.
Python3
# import all the libraries from PIL import Image from PIL import ImageFont from PIL import ImageDraw # image opening image = Image.open("image.jpg") # creating a copy of original image watermark_image = image.copy() # Image is converted into editable form using # Draw function and assigned to draw draw = ImageDraw.Draw(watermark_image) # ("font type",font size) font = ImageFont.truetype("DroidSans.ttf", 50) # Decide the text location, color and font # (255,255,255)-White color text draw.text((0, 0), "GeeksforGeeks", (255, 255, 255), font=font) watermark_image.show()
Producción:
- Haz que la imagen sea editable usando ImageDraw .
- Utilice ImageFont para especificar la fuente y el tamaño de la fuente. Este paso es opcional. Es para aquellos que quieren que su texto se vea genial o con estilo porque alguien no seleccionará ningún estilo de fuente, entonces el sistema toma el estilo de fuente predeterminado.
- Cree una fuente usando la función del módulo ImageFont truetype() ya que necesita dos parámetros que son («tipo de fuente», tamaño)
- Luego usó la función text() del objeto de dibujo y pasó los cuatro parámetros (Punto de inicio para el texto, «texto de muestra», Color, objeto ImageFont).
Consulte los artículos a continuación para obtener información detallada sobre cómo agregar textos a la imagen.
- Python Pillow – Escribir texto en la imagen
- Python PIL | ImageDraw.Draw.text()
- Agregar texto en la imagen usando Python – PIL
Adición de textos de varias líneas
ImageDraw.Draw.multiline_text() se usa para dibujar la string en la posición dada.
Sintaxis:
ImageDraw.Draw.multiline_text(xy, texto, relleno=Ninguno, fuente=Ninguno, ancla=Ninguno, espaciado=0, alineación=”izquierda”)
Ejemplo:
Python3
# Importing Image and ImageFont, ImageDraw # module from PIL package from PIL import Image, ImageFont, ImageDraw # creating a image object image = Image.open(r'geek.jpg') draw = ImageDraw.Draw(image) # specified font size font = ImageFont.truetype(r'DroidSans.ttf', 15) text = u"""\ Geeks FOR \n Geeks""" # drawing text size draw.text((6, 8), text, fill ="red", font = font, align ="right") image.show()
Producción:
línea de dibujo
ImageDraw.Draw.line() se usa para dibujar una línea entre las coordenadas en la lista xy.
Sintaxis:
ImageDraw.Draw.line(xy, relleno=Ninguno, ancho=0)
Ejemplo:
Python3
# importing image object from PIL import math from PIL import Image, ImageDraw w, h = 220, 190 shape = [(40, 40), (w - 10, h - 10)] # creating new Image object img = Image.new("RGB", (w, h)) # create line image img1 = ImageDraw.Draw(img) img1.line(shape, fill="none", width=0) img.show()
Producción:
Rectángulo de dibujo
ImageDraw.Draw.rectangle() se usa para dibujar un rectángulo.
Sintaxis:
ImageDraw.Draw.rectangle(xy, relleno=Ninguno, contorno=Ninguno)
Ejemplo:
Python3
# importing image object from PIL import math from PIL import Image, ImageDraw w, h = 220, 190 shape = [(40, 40), (w - 10, h - 10)] # creating new Image object img = Image.new("RGB", (w, h)) # create rectangle image img1 = ImageDraw.Draw(img) img1.rectangle(shape, fill="# ffff33", outline="red") img.show()
Producción:
Dibujar polígono
ImageDraw.Draw.polygon() se usa para dibujar un polígono. El contorno del polígono consta de líneas rectas entre las coordenadas dadas, más una línea recta entre la última y la primera coordenada.
Sintaxis:
ImageDraw.Draw.polygon(xy, relleno=Ninguno, contorno=Ninguno)
Ejemplo:
Python3
import math from PIL import Image, ImageDraw from PIL import ImagePath side = 8 xy = [ ((math.cos(th) + 1) * 90, (math.sin(th) + 1) * 60) for th in [i * (2 * math.pi) / side for i in range(side)] ] image = ImagePath.Path(xy).getbbox() size = list(map(int, map(math.ceil, image[2:]))) img = Image.new("RGB", size, "# f9f9f9") img1 = ImageDraw.Draw(img) img1.polygon(xy, fill="# eeeeff", outline="blue") img.show()
Producción:
Imagen mejorada
Python Pillow proporciona el módulo ImageEnhance para ajustar el color, el brillo, el contraste y la nitidez de la imagen.
Ajuste de color y contraste
Los métodos ImageEnhance.Color() e ImageEnhance.Contrast() se utilizan para ajustar el color y el contraste de la imagen respectivamente.
- ImageEnhance.Color() se utiliza para ajustar el balance de color de una imagen, de forma similar a los controles de un televisor en color. Un factor de mejora de 0,0 da una imagen en blanco y negro. Un factor de 1,0 da la imagen original.
Sintaxis:
ImageEnhance.Color(imagen)
Ejemplo:
Python3
# This will import Image and ImageEnhance modules from PIL import Image, ImageEnhance # Opening Image im = Image.open(r"geek.jpg") # Creating object of Color class im3 = ImageEnhance.Color(im) # showing resultant image im3.enhance(5.0).show()
Producción:
- ImageEnhance.Contrast() se usa para controlar el contraste de una imagen, similar al control de contraste en un televisor. Un factor de mejora de 0,0 da una imagen gris sólida. Un factor de 1,0 da la imagen original.
Sintaxis:
obj = ImageEnhance.Contrast(imagen)
obj.enhance(factor)
Ejemplo:
Python3
# This will import Image and ImageEnhance modules from PIL import Image, ImageEnhance # Opening Image im = Image.open(r"geek.jpg") # Creating object of Contrast class im3 = ImageEnhance.Contrast(im) # showing resultant image im3.enhance(5.0).show()
Producción:
Consulte los siguientes artículos para obtener información detallada sobre cómo mejorar el color y el contraste.
Ajuste de brillo y nitidez
Los métodos ImageEnhance.Brightness() e ImageEnhance.Sharpness() se utilizan para ajustar el brillo y la nitidez de la imagen.
- ImageEnhance.Brightness() se utiliza para controlar el brillo de una imagen. Un factor de mejora de 0,0 da una imagen negra. Un factor de 1,0 da la imagen original.
Sintaxis:
obj = ImageEnhance.Brightness(imagen)
obj.enhance(factor)
Ejemplo:
Python3
# This will import Image and ImageEnhance modules from PIL import Image, ImageEnhance # Opening Image im = Image.open(r"geek.jpg") # Creating object of Brightness class im3 = ImageEnhance.Brightness(im) # showing resultant image im3.enhance(1.5).show()
Producción:
- ImageEnhance.Sharpness() se utiliza para ajustar la nitidez de una imagen. Un factor de mejora de 0,0 da una imagen borrosa, un factor de 1,0 da la imagen original y un factor de 2,0 da una imagen más nítida.
Sintaxis:
obj = ImageEnhance.Sharpness(imagen)
obj.enhance(factor)
Ejemplo:
Python3
# This will import Image and ImageChops modules from PIL import Image, ImageEnhance # Opening Image im = Image.open(r"geek.jpg") # Creating object of Sharpness class im3 = ImageEnhance.Sharpness(im) # showing resultant image im3.enhance(5.0).show()
Producción:
Consulte los siguientes artículos para obtener información detallada sobre cómo mejorar el brillo y la nitidez de la imagen.
Convierte imágenes entre varios formatos
- Convierta el .GIF a .BMP y viceversa en Python
- Convierte una imagen a formato jpg usando Pillow en Python
- Convierte PNG a JPG usando Python
- Convierta archivos de jpg a png y viceversa usando Python
- Convierta .PNG a .GIF y viceversa en Python
- Convierta archivos de jpg a gif y viceversa usando Python
- Convertir imagen OpenCV a imagen PIL en Python
Operaciones avanzadas en la imagen usando Pillow
- Crear imagen png transparente con Python – Pillow
- Añadir relleno a la imagen con Python – Pillow
- Encuentre los colores más utilizados en la imagen usando Python
- Python – Inversión de color usando Pillow
- Superponer una imagen en otra imagen en Python
- Cambiar la resolución de la imagen usando Pillow en Python
- Encuentra la diferencia entre dos imágenes usando Python
- ¿Cómo extraer texto de imágenes con Python?
- Crea y guarda GIF animados con Python – Pillow
- ¿Cómo comprimir imágenes usando Python y PIL?
- Python | Usando PIL ImageGrab y PyTesseract
- Imagen de relleno con Python-Pillow
- Python – Caída de canal usando Pillow
Ejercicios y aplicaciones de Python Pillow
- Cargando Imágenes en Tkinter usando PIL
- Crear certificados usando Python-PIL
- Python | OCR en Todas las Imágenes presentes en una Carpeta Simultáneamente
- Aplicar cambios a todas las imágenes en la carpeta dada – Usando Python PIL
Publicación traducida automáticamente
Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA